2 Copyright (c) 2006, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 Common Library Routines to assist in IFR creation on-the-fly
25 IN EFI_HANDLE ImageHandle
,
26 IN EFI_SYSTEM_TABLE
*SystemTable
40 Determine what is the current language setting
44 Lang - Pointer of system language
58 // Getting the system language and placing it into our Global Data
60 Size
= sizeof (Language
);
62 Status
= gRT
->GetVariable (
64 &gEfiGlobalVariableGuid
,
70 if (EFI_ERROR (Status
)) {
71 AsciiStrCpy (Language
, "eng");
74 for (Index
= 0; Index
< 3; Index
++) {
76 // Bitwise AND ascii value with 0xDF yields an uppercase value.
77 // Sign extend into a unicode value
79 Lang
[Index
] = (CHAR16
) (Language
[Index
] & 0xDF);
83 // Null-terminate the value
93 IN VOID
*StringBuffer
,
96 IN OUT STRING_REF
*StringToken
102 Add a string to the incoming buffer and return the token and offset data
106 StringBuffer - The incoming buffer
108 Language - Currrent language
110 String - The string to be added
112 StringToken - The index where the string placed
116 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
118 EFI_SUCCESS - String successfully added to the incoming buffer
122 EFI_HII_STRING_PACK
*StringPack
;
123 EFI_HII_STRING_PACK
*StringPackBuffer
;
126 RELOFST
*PackDestination
;
131 UINTN SizeofLanguage
;
134 StringPack
= (EFI_HII_STRING_PACK
*) StringBuffer
;
138 // Pre-allocate a buffer sufficient for us to work on.
139 // We will use it as a destination scratch pad to build data on
140 // and when complete shift the data back to the original buffer
142 NewBuffer
= AllocateZeroPool (DEFAULT_STRING_BUFFER_SIZE
);
143 if (NewBuffer
== NULL
) {
144 return EFI_OUT_OF_RESOURCES
;
147 StringPackBuffer
= (EFI_HII_STRING_PACK
*) NewBuffer
;
150 // StringPack is terminated with a length 0 entry
152 for (; StringPack
->Header
.Length
!= 0;) {
154 // If this stringpack's language is same as CurrentLanguage, use it
156 if (CompareMem ((VOID
*) ((CHAR8
*) (StringPack
) + StringPack
->LanguageNameString
), Language
, 3) == 0) {
158 // We have some data in this string pack, copy the string package up to the string data
160 CopyMem (&StringPackBuffer
->Header
, &StringPack
->Header
, sizeof (StringPack
));
163 // These are references in the structure to tokens, need to increase them by the space occupied by an additional StringPointer
165 StringPackBuffer
->LanguageNameString
= (UINT16
) (StringPackBuffer
->LanguageNameString
+ (UINT16
) sizeof (RELOFST
));
166 StringPackBuffer
->PrintableLanguageName
= (UINT16
) (StringPackBuffer
->PrintableLanguageName
+ (UINT16
) sizeof (RELOFST
));
168 PackSource
= (RELOFST
*) (StringPack
+ 1);
169 PackDestination
= (RELOFST
*) (StringPackBuffer
+ 1);
170 for (Index
= 0; PackSource
[Index
] != 0x0000; Index
++) {
172 // Copy the stringpointers from old to new buffer
173 // remember that we are adding a string, so the string offsets will all go up by sizeof (RELOFST)
175 PackDestination
[Index
] = (UINT16
) (PackDestination
[Index
] + sizeof (RELOFST
));
179 // Add a new stringpointer in the new buffer since we are adding a string. Null terminate it
181 PackDestination
[Index
] = (UINT16
)(PackDestination
[Index
-1] +
182 StrSize((CHAR16
*)((CHAR8
*)(StringPack
) + PackSource
[Index
-1])));
183 PackDestination
[Index
+ 1] = (UINT16
) 0;
186 // Index is the token value for the new string
188 *StringToken
= (UINT16
) Index
;
191 // Source now points to the beginning of the old buffer strings
192 // Destination now points to the beginning of the new buffer strings
194 Source
= (UINT8
*) &PackSource
[Index
+ 1];
195 Destination
= (UINT8
*) &PackDestination
[Index
+ 2];
198 // This should copy all the strings from the old buffer to the new buffer
200 for (; Index
!= 0; Index
--) {
202 // Copy Source string to destination buffer
204 StrCpy ((CHAR16
*) Destination
, (CHAR16
*) Source
);
207 // Adjust the source/destination to the next string location
209 Destination
= Destination
+ StrSize ((CHAR16
*) Source
);
210 Source
= Source
+ StrSize ((CHAR16
*) Source
);
214 // This copies the new string to the destination buffer
216 StrCpy ((CHAR16
*) Destination
, (CHAR16
*) String
);
219 // Adjust the size of the changed string pack by adding the size of the new string
220 // along with the size of the additional offset entry for the new string
222 StringPackBuffer
->Header
.Length
= (UINT32
) ((UINTN
) StringPackBuffer
->Header
.Length
+ StrSize (String
) + sizeof (RELOFST
));
225 // Advance the buffers to point to the next spots.
227 StringPackBuffer
= (EFI_HII_STRING_PACK
*) ((CHAR8
*) (StringPackBuffer
) + StringPackBuffer
->Header
.Length
);
228 StringPack
= (EFI_HII_STRING_PACK
*) ((CHAR8
*) (StringPack
) + StringPack
->Header
.Length
);
233 // This isn't the language of the stringpack we were asked to add a string to
234 // so we need to copy it to the new buffer.
236 CopyMem (&StringPackBuffer
->Header
, &StringPack
->Header
, StringPack
->Header
.Length
);
239 // Advance the buffers to point to the next spots.
241 StringPackBuffer
= (EFI_HII_STRING_PACK
*) ((CHAR8
*) (StringPackBuffer
) + StringPack
->Header
.Length
);
242 StringPack
= (EFI_HII_STRING_PACK
*) ((CHAR8
*) (StringPack
) + StringPack
->Header
.Length
);
246 // If we didn't copy the new data to a stringpack yet
249 PackDestination
= (RELOFST
*) (StringPackBuffer
+ 1);
251 // Pointing to a new string pack location
253 SizeofLanguage
= StrSize (Language
);
254 SizeofString
= StrSize (String
);
255 StringPackBuffer
->Header
.Length
= (UINT32
)
257 sizeof (EFI_HII_STRING_PACK
) -
258 sizeof (EFI_STRING
) +
264 StringPackBuffer
->Header
.Type
= EFI_HII_STRING
;
265 StringPackBuffer
->LanguageNameString
= (UINT16
) ((UINTN
) &PackDestination
[3] - (UINTN
) StringPackBuffer
);
266 StringPackBuffer
->PrintableLanguageName
= (UINT16
) ((UINTN
) &PackDestination
[3] - (UINTN
) StringPackBuffer
);
267 StringPackBuffer
->Attributes
= 0;
268 PackDestination
[0] = (UINT16
) ((UINTN
) &PackDestination
[3] - (UINTN
) StringPackBuffer
);
269 PackDestination
[1] = (UINT16
) (PackDestination
[0] + StrSize (Language
));
270 PackDestination
[2] = (UINT16
) 0;
273 // The first string location will be set to destination. The minimum number of strings
274 // associated with a stringpack will always be token 0 stored as the languagename (e.g. ENG, SPA, etc)
275 // and token 1 as the new string being added and and null entry for the stringpointers
277 Destination
= (UINT8
*) &PackDestination
[3];
280 // Copy the language name string to the new buffer
282 StrCpy ((CHAR16
*) Destination
, Language
);
285 // Advance the destination to the new empty spot
287 Destination
= Destination
+ StrSize (Language
);
290 // Copy the string to the new buffer
292 StrCpy ((CHAR16
*) Destination
, String
);
295 // Since we are starting with a new string pack - we know the new string is token 1
297 *StringToken
= (UINT16
) 1;
301 // Zero out the original buffer and copy the updated data in the new buffer to the old buffer
303 ZeroMem (StringBuffer
, DEFAULT_STRING_BUFFER_SIZE
);
304 CopyMem (StringBuffer
, NewBuffer
, DEFAULT_STRING_BUFFER_SIZE
);
307 // Free the newly created buffer since we don't need it anymore
309 gBS
->FreePool (NewBuffer
);
317 IN OUT VOID
*OpCodeData
323 Add op-code data to the FormBuffer
327 FormBuffer - Form buffer to be inserted to
329 OpCodeData - Op-code data to be inserted
333 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
335 EFI_SUCCESS - Op-code data successfully inserted
339 EFI_HII_PACK_HEADER
*NewBuffer
;
344 // Pre-allocate a buffer sufficient for us to work on.
345 // We will use it as a destination scratch pad to build data on
346 // and when complete shift the data back to the original buffer
348 NewBuffer
= AllocateZeroPool (DEFAULT_FORM_BUFFER_SIZE
);
349 if (NewBuffer
== NULL
) {
350 return EFI_OUT_OF_RESOURCES
;
353 Source
= (UINT8
*) FormBuffer
;
354 Destination
= (UINT8
*) NewBuffer
;
357 // Copy the IFR Package header to the new buffer
359 CopyMem (Destination
, Source
, sizeof (EFI_HII_PACK_HEADER
));
362 // Advance Source and Destination to next op-code
364 Source
= Source
+ sizeof (EFI_HII_PACK_HEADER
);
365 Destination
= Destination
+ sizeof (EFI_HII_PACK_HEADER
);
368 // Copy data to the new buffer until we run into the end_form
370 for (; ((EFI_IFR_OP_HEADER
*) Source
)->OpCode
!= EFI_IFR_END_FORM_OP
;) {
372 // If the this opcode is an end_form_set we better be creating and endform
373 // Nonetheless, we will add data before the end_form_set. This also provides
374 // for interesting behavior in the code we will run, but has no bad side-effects
375 // since we will possibly do a 0 byte copy in this particular end-case.
377 if (((EFI_IFR_OP_HEADER
*) Source
)->OpCode
== EFI_IFR_END_FORM_SET_OP
) {
382 // Copy data to new buffer
384 CopyMem (Destination
, Source
, ((EFI_IFR_OP_HEADER
*) Source
)->Length
);
387 // Adjust Source/Destination to next op-code location
389 Destination
= Destination
+ (UINTN
) ((EFI_IFR_OP_HEADER
*) Source
)->Length
;
390 Source
= Source
+ (UINTN
) ((EFI_IFR_OP_HEADER
*) Source
)->Length
;
394 // Prior to the end_form is where we insert the new op-code data
396 CopyMem (Destination
, OpCodeData
, ((EFI_IFR_OP_HEADER
*) OpCodeData
)->Length
);
397 Destination
= Destination
+ (UINTN
) ((EFI_IFR_OP_HEADER
*) OpCodeData
)->Length
;
399 NewBuffer
->Length
= (UINT32
) (NewBuffer
->Length
+ (UINT32
) (((EFI_IFR_OP_HEADER
*) OpCodeData
)->Length
));
402 // Copy end-form data to new buffer
404 CopyMem (Destination
, Source
, ((EFI_IFR_OP_HEADER
*) Source
)->Length
);
407 // Adjust Source/Destination to next op-code location
409 Destination
= Destination
+ (UINTN
) ((EFI_IFR_OP_HEADER
*) Source
)->Length
;
410 Source
= Source
+ (UINTN
) ((EFI_IFR_OP_HEADER
*) Source
)->Length
;
413 // Copy end-formset data to new buffer
415 CopyMem (Destination
, Source
, ((EFI_IFR_OP_HEADER
*) Source
)->Length
);
418 // Zero out the original buffer and copy the updated data in the new buffer to the old buffer
420 ZeroMem (FormBuffer
, DEFAULT_FORM_BUFFER_SIZE
);
421 CopyMem (FormBuffer
, NewBuffer
, DEFAULT_FORM_BUFFER_SIZE
);
424 // Free the newly created buffer since we don't need it anymore
426 gBS
->FreePool (NewBuffer
);
433 OUT EFI_HII_PROTOCOL
**Hii
439 Get the HII protocol interface
443 Hii - HII protocol interface
454 // There should only be one HII protocol
456 Status
= gBS
->LocateProtocol (
457 &gEfiHiiProtocolGuid
,
467 ExtractDataFromHiiHandle (
468 IN EFI_HII_HANDLE HiiHandle
,
469 IN OUT UINT16
*ImageLength
,
470 OUT UINT8
*DefaultImage
,
477 Extract information pertaining to the HiiHandle
481 HiiHandle - Hii handle
483 ImageLength - For input, length of DefaultImage;
484 For output, length of actually required
486 DefaultImage - Image buffer prepared by caller
488 Guid - Guid information about the form
492 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
494 EFI_BUFFER_TOO_SMALL - DefualtImage has no enough ImageLength
496 EFI_SUCCESS - Successfully extract data from Hii database.
502 EFI_HII_PROTOCOL
*Hii
;
511 DataLength
= DEFAULT_FORM_BUFFER_SIZE
;
515 Status
= GetHiiInterface (&Hii
);
517 if (EFI_ERROR (Status
)) {
522 // Allocate space for retrieval of IFR data
524 RawData
= AllocateZeroPool (DataLength
);
525 if (RawData
== NULL
) {
526 return EFI_OUT_OF_RESOURCES
;
530 // Get all the forms associated with this HiiHandle
532 Status
= Hii
->GetForms (Hii
, HiiHandle
, 0, &DataLength
, RawData
);
534 if (EFI_ERROR (Status
)) {
535 gBS
->FreePool (RawData
);
538 // Allocate space for retrieval of IFR data
540 RawData
= AllocateZeroPool (DataLength
);
541 if (RawData
== NULL
) {
542 return EFI_OUT_OF_RESOURCES
;
546 // Get all the forms associated with this HiiHandle
548 Status
= Hii
->GetForms (Hii
, HiiHandle
, 0, &DataLength
, RawData
);
554 // Point RawData to the beginning of the form data
556 RawData
= (UINT8
*) ((UINTN
) RawData
+ sizeof (EFI_HII_PACK_HEADER
));
558 for (Index
= 0; RawData
[Index
] != EFI_IFR_END_FORM_SET_OP
;) {
559 switch (RawData
[Index
]) {
560 case EFI_IFR_FORM_SET_OP
:
562 // Copy the GUID information from this handle
564 CopyMem (Guid
, &((EFI_IFR_FORM_SET
*) &RawData
[Index
])->Guid
, sizeof (EFI_GUID
));
567 case EFI_IFR_ONE_OF_OP
:
568 case EFI_IFR_CHECKBOX_OP
:
569 case EFI_IFR_NUMERIC_OP
:
570 case EFI_IFR_DATE_OP
:
571 case EFI_IFR_TIME_OP
:
572 case EFI_IFR_PASSWORD_OP
:
573 case EFI_IFR_STRING_OP
:
575 // Remember, multiple op-codes may reference the same item, so let's keep a running
576 // marker of what the highest QuestionId that wasn't zero length. This will accurately
577 // maintain the Size of the NvStore
579 if (((EFI_IFR_ONE_OF
*) &RawData
[Index
])->Width
!= 0) {
580 Temp
= ((EFI_IFR_ONE_OF
*) &RawData
[Index
])->QuestionId
+ ((EFI_IFR_ONE_OF
*) &RawData
[Index
])->Width
;
581 if (SizeOfNvStore
< Temp
) {
582 SizeOfNvStore
= ((EFI_IFR_ONE_OF
*) &RawData
[Index
])->QuestionId
+ ((EFI_IFR_ONE_OF
*) &RawData
[Index
])->Width
;
587 Index
= RawData
[Index
+ 1] + Index
;
591 // Return an error if buffer is too small
593 if (SizeOfNvStore
> *ImageLength
) {
594 gBS
->FreePool (OldData
);
595 *ImageLength
= (UINT16
) SizeOfNvStore
;
596 return EFI_BUFFER_TOO_SMALL
;
599 if (DefaultImage
!= NULL
) {
600 ZeroMem (DefaultImage
, SizeOfNvStore
);
604 // Copy the default image information to the user's buffer
606 for (Index
= 0; RawData
[Index
] != EFI_IFR_END_FORM_SET_OP
;) {
607 switch (RawData
[Index
]) {
608 case EFI_IFR_ONE_OF_OP
:
609 CachedStart
= ((EFI_IFR_ONE_OF
*) &RawData
[Index
])->QuestionId
;
612 case EFI_IFR_ONE_OF_OPTION_OP
:
613 if (((EFI_IFR_ONE_OF_OPTION
*) &RawData
[Index
])->Flags
& EFI_IFR_FLAG_DEFAULT
) {
614 CopyMem (&DefaultImage
[CachedStart
], &((EFI_IFR_ONE_OF_OPTION
*) &RawData
[Index
])->Value
, 2);
618 case EFI_IFR_CHECKBOX_OP
:
619 DefaultImage
[((EFI_IFR_ONE_OF
*) &RawData
[Index
])->QuestionId
] = ((EFI_IFR_CHECKBOX
*) &RawData
[Index
])->Flags
;
622 case EFI_IFR_NUMERIC_OP
:
624 &DefaultImage
[((EFI_IFR_ONE_OF
*) &RawData
[Index
])->QuestionId
],
625 &((EFI_IFR_NUMERIC
*) &RawData
[Index
])->Default
,
632 Index
= RawData
[Index
+ 1] + Index
;
635 *ImageLength
= (UINT16
) SizeOfNvStore
;
638 // Free our temporary repository of form data
640 gBS
->FreePool (OldData
);
648 IN OUT EFI_HII_PROTOCOL
**HiiProtocol
, OPTIONAL
654 Finds HII handle for given pack GUID previously registered with the HII.
657 HiiProtocol - pointer to pointer to HII protocol interface.
658 If NULL, the interface will be found but not returned.
659 If it points to NULL, the interface will be found and
660 written back to the pointer that is pointed to.
661 Guid - The GUID of the pack that registered with the HII.
664 Handle to the HII pack previously registered by the memory driver.
670 EFI_HII_HANDLE
*HiiHandleBuffer
;
671 EFI_HII_HANDLE HiiHandle
;
672 UINT16 HiiHandleBufferLength
;
673 UINT32 NumberOfHiiHandles
;
675 EFI_HII_PROTOCOL
*HiiProt
;
680 if ((HiiProtocol
!= NULL
) && (*HiiProtocol
!= NULL
)) {
682 // The protocol has been passed in
684 HiiProt
= *HiiProtocol
;
686 gBS
->LocateProtocol (
687 &gEfiHiiProtocolGuid
,
691 if (HiiProt
== NULL
) {
695 if (HiiProtocol
!= NULL
) {
697 // Return back the HII protocol for the caller as promissed
699 *HiiProtocol
= HiiProt
;
705 HiiHandleBufferLength
= 10;
706 HiiHandleBuffer
= AllocatePool (HiiHandleBufferLength
);
707 ASSERT (HiiHandleBuffer
!= NULL
);
710 // Get the Handles of the packages that were registered with Hii
712 Status
= HiiProt
->FindHandles (
714 &HiiHandleBufferLength
,
719 // Get a bigger bugffer if this one is to small, and try again
721 if (Status
== EFI_BUFFER_TOO_SMALL
) {
723 gBS
->FreePool (HiiHandleBuffer
);
725 HiiHandleBuffer
= AllocatePool (HiiHandleBufferLength
);
726 ASSERT (HiiHandleBuffer
!= NULL
);
728 Status
= HiiProt
->FindHandles (
730 &HiiHandleBufferLength
,
735 if (EFI_ERROR (Status
)) {
739 NumberOfHiiHandles
= HiiHandleBufferLength
/ sizeof (EFI_HII_HANDLE
);
742 // Iterate Hii handles and look for the one that matches our Guid
744 for (Index
= 0; Index
< NumberOfHiiHandles
; Index
++) {
747 ExtractDataFromHiiHandle (HiiHandleBuffer
[Index
], &Length
, NULL
, &HiiGuid
);
749 if (CompareGuid (&HiiGuid
, Guid
)) {
751 HiiHandle
= HiiHandleBuffer
[Index
];
757 gBS
->FreePool (HiiHandleBuffer
);
763 ValidateDataFromHiiHandle (
764 IN EFI_HII_HANDLE HiiHandle
,
771 Validate that the data associated with the HiiHandle in NVRAM is within
772 the reasonable parameters for that FormSet. Values for strings and passwords
773 are not verified due to their not having the equivalent of valid range settings.
777 HiiHandle - Handle of the HII database entry to query
779 Results - If return Status is EFI_SUCCESS, Results provides valid data
780 TRUE = NVRAM Data is within parameters
781 FALSE = NVRAM Data is NOT within parameters
785 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
787 EFI_SUCCESS - Data successfully validated
791 EFI_HII_PROTOCOL
*Hii
;
803 RawDataLength
= DEFAULT_FORM_BUFFER_SIZE
;
809 Status
= GetHiiInterface (&Hii
);
811 if (EFI_ERROR (Status
)) {
816 // Allocate space for retrieval of IFR data
818 RawData
= AllocateZeroPool (RawDataLength
);
819 if (RawData
== NULL
) {
820 return EFI_OUT_OF_RESOURCES
;
824 // Get all the forms associated with this HiiHandle
826 Status
= Hii
->GetForms (Hii
, HiiHandle
, 0, &RawDataLength
, RawData
);
828 if (EFI_ERROR (Status
)) {
829 gBS
->FreePool (RawData
);
832 // Allocate space for retrieval of IFR data
834 RawData
= AllocateZeroPool (RawDataLength
);
835 if (RawData
== NULL
) {
836 return EFI_OUT_OF_RESOURCES
;
840 // Get all the forms associated with this HiiHandle
842 Status
= Hii
->GetForms (Hii
, HiiHandle
, 0, &RawDataLength
, RawData
);
848 // Point RawData to the beginning of the form data
850 RawData
= (UINT8
*) ((UINTN
) RawData
+ sizeof (EFI_HII_PACK_HEADER
));
852 for (Index
= 0; RawData
[Index
] != EFI_IFR_END_FORM_SET_OP
;) {
853 if (RawData
[Index
] == EFI_IFR_FORM_SET_OP
) {
854 CopyMem (&Guid
, &((EFI_IFR_FORM_SET
*) &RawData
[Index
])->Guid
, sizeof (EFI_GUID
));
858 Index
= RawData
[Index
+ 1] + Index
;
861 for (Index
= 0; RawData
[Index
] != EFI_IFR_END_FORM_SET_OP
;) {
862 switch (RawData
[Index
]) {
863 case EFI_IFR_FORM_SET_OP
:
866 case EFI_IFR_ONE_OF_OP
:
867 case EFI_IFR_CHECKBOX_OP
:
868 case EFI_IFR_NUMERIC_OP
:
869 case EFI_IFR_DATE_OP
:
870 case EFI_IFR_TIME_OP
:
871 case EFI_IFR_PASSWORD_OP
:
872 case EFI_IFR_STRING_OP
:
874 // Remember, multiple op-codes may reference the same item, so let's keep a running
875 // marker of what the highest QuestionId that wasn't zero length. This will accurately
876 // maintain the Size of the NvStore
878 if (((EFI_IFR_ONE_OF
*) &RawData
[Index
])->Width
!= 0) {
879 Temp
= ((EFI_IFR_ONE_OF
*) &RawData
[Index
])->QuestionId
+ ((EFI_IFR_ONE_OF
*) &RawData
[Index
])->Width
;
880 if (SizeOfNvStore
< Temp
) {
881 SizeOfNvStore
= ((EFI_IFR_ONE_OF
*) &RawData
[Index
])->QuestionId
+ ((EFI_IFR_ONE_OF
*) &RawData
[Index
])->Width
;
886 Index
= RawData
[Index
+ 1] + Index
;
890 // Allocate memory for our File Form Tags
892 VariableData
= AllocateZeroPool (SizeOfNvStore
);
893 if (VariableData
== NULL
) {
894 return EFI_OUT_OF_RESOURCES
;
897 Status
= gRT
->GetVariable (
902 (VOID
*) VariableData
905 if (EFI_ERROR (Status
)) {
908 // If there is a variable that exists already and it is larger than what we calculated the
909 // storage needs to be, we must assume the variable size from GetVariable is correct and not
910 // allow the truncation of the variable. It is very possible that the user who created the IFR
911 // we are cracking is not referring to a variable that was in a previous map, however we cannot
912 // allow it's truncation.
914 if (Status
== EFI_BUFFER_TOO_SMALL
) {
916 // Free the buffer that was allocated that was too small
918 gBS
->FreePool (VariableData
);
920 VariableData
= AllocatePool (SizeOfNvStore
);
921 if (VariableData
== NULL
) {
922 return EFI_OUT_OF_RESOURCES
;
925 Status
= gRT
->GetVariable (
930 (VOID
*) VariableData
936 // Walk through the form and see that the variable data it refers to is ok.
937 // This allows for the possibility of stale (obsoleted) data in the variable
938 // can be overlooked without causing an error
940 for (Index
= 0; RawData
[Index
] != EFI_IFR_END_FORM_SET_OP
;) {
941 switch (RawData
[Index
]) {
942 case EFI_IFR_ONE_OF_OP
:
944 // A one_of has no data, its the option that does - cache the storage Id
946 CachedStart
= ((EFI_IFR_ONE_OF
*) &RawData
[Index
])->QuestionId
;
949 case EFI_IFR_ONE_OF_OPTION_OP
:
951 // A one_of_option can be any value
953 if (VariableData
[CachedStart
] == ((EFI_IFR_ONE_OF_OPTION
*) &RawData
[Index
])->Value
) {
958 case EFI_IFR_END_ONE_OF_OP
:
960 // At this point lets make sure that the data value in the NVRAM matches one of the options
968 case EFI_IFR_CHECKBOX_OP
:
970 // A checkbox is a boolean, so 0 and 1 are valid
971 // Remember, QuestionId corresponds to the offset location of the data in the variable
973 if (VariableData
[((EFI_IFR_CHECKBOX
*) &RawData
[Index
])->QuestionId
] > 1) {
979 case EFI_IFR_NUMERIC_OP
:
980 if ((VariableData
[((EFI_IFR_NUMERIC
*)&RawData
[Index
])->QuestionId
] < ((EFI_IFR_NUMERIC
*)&RawData
[Index
])->Minimum
) ||
981 (VariableData
[((EFI_IFR_NUMERIC
*)&RawData
[Index
])->QuestionId
] > ((EFI_IFR_NUMERIC
*)&RawData
[Index
])->Maximum
)) {
989 Index
= RawData
[Index
+ 1] + Index
;
993 // Free our temporary repository of form data
995 gBS
->FreePool (OldData
);
996 gBS
->FreePool (VariableData
);