2 Entry and initialization module for the browser.
4 Copyright (c) 2006 - 2007 Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 FUNCTIION_KEY_SETTING gFunctionKeySettingTable
[] = {
38 NONE_FUNCTION_KEY_SETTING
59 NONE_FUNCTION_KEY_SETTING
80 NONE_FUNCTION_KEY_SETTING
83 // BMM File Explorer Formset.
101 NONE_FUNCTION_KEY_SETTING
107 InitializeBinaryStructures (
108 IN EFI_HII_HANDLE
*Handle
,
109 IN BOOLEAN UseDatabase
,
110 IN EFI_IFR_PACKET
*Packet
,
111 IN UINT8
*NvMapOverride
,
112 IN UINTN NumberOfIfrImages
,
113 EFI_FILE_FORM_TAGS
**FileFormTagsHead
118 InitializeTagStructures (
119 IN EFI_IFR_BINARY
*BinaryData
,
120 OUT EFI_FILE_FORM_TAGS
*FileFormTags
126 IN UINTN NumberOfIfrImages
,
127 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
128 IN UINT8
*CallbackData
134 IN EFI_HII_PROTOCOL
*Hii
,
135 IN EFI_HII_HANDLE HiiHandle
,
136 IN EFI_IFR_PACKET
*Packet
,
137 IN EFI_IFR_BINARY
*BinaryData
150 IN EFI_FORM_BROWSER_PROTOCOL
* This
,
151 IN BOOLEAN UseDatabase
,
152 IN EFI_HII_HANDLE
* Handle
,
153 IN UINTN HandleCount
,
154 IN EFI_IFR_PACKET
* Packet
,
155 IN EFI_HANDLE CallbackHandle
,
156 IN UINT8
*NvMapOverride
,
157 IN EFI_SCREEN_DESCRIPTOR
*ScreenDimensions
, OPTIONAL
158 OUT BOOLEAN
*ResetRequired OPTIONAL
164 This is the routine which an external caller uses to direct the browser
165 where to obtain it's information.
169 UseDatabase - If set to TRUE, then all information is retrieved from the HII database handle specified
170 If set to FALSE, then the passed in Packet and CallbackHandle is used and Handle is ignored
172 Handle - A pointer to an array of Handles. If HandleCount > 1 we display a list of the formsets for the handles specified
174 HandleCount - The number of Handles specified in Handle.
176 Packet - Valid only if UseDatabase is FALSE. Packet defines the pages being passed into
177 the browser. This is composed of IFR data as well as String information.
179 CallbackHandle - The handle which contains the calling driver's EFI_FORM_CALLBACK_PROTOCOL interface.
181 ScreenDimenions - This allows the browser to be called so that it occupies a portion of the physical screen instead of
182 dynamically determining the screen dimensions.
184 NvMapOverride - This buffer is used only when there is no NV variable to define the current settings and the caller
185 needs to provide to the browser the current settings for the "fake" NV variable. If used, no saving
186 of an NV variable will be possible. This parameter is also ignored if HandleCount > 1.
192 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
193 EFI_FILE_FORM_TAGS
*FileFormTagsHead
;
194 UI_MENU_OPTION
*Selection
;
195 UI_MENU_OPTION
*AltSelection
;
199 EFI_HII_HANDLE BackupHandle
;
201 ZeroMem (&gScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
203 gPreviousValue
= AllocatePool (0x1000);
204 CallbackData
= AllocatePool (0x10000);
205 ASSERT (gPreviousValue
!= NULL
);
206 ASSERT (CallbackData
!= NULL
);
210 // Seed the dimensions in the global
212 gST
->ConOut
->QueryMode (
214 gST
->ConOut
->Mode
->Mode
,
215 &gScreenDimensions
.RightColumn
,
216 &gScreenDimensions
.BottomRow
219 if (ScreenDimensions
!= NULL
) {
221 // Check local dimension vs. global dimension.
223 if ((gScreenDimensions
.RightColumn
< ScreenDimensions
->RightColumn
) ||
224 (gScreenDimensions
.BottomRow
< ScreenDimensions
->BottomRow
)
226 return EFI_INVALID_PARAMETER
;
229 // Local dimension validation.
231 if ((ScreenDimensions
->RightColumn
> ScreenDimensions
->LeftColumn
) &&
232 (ScreenDimensions
->BottomRow
> ScreenDimensions
->TopRow
) &&
233 ((ScreenDimensions
->RightColumn
- ScreenDimensions
->LeftColumn
) > 2) &&
235 (ScreenDimensions
->BottomRow
- ScreenDimensions
->TopRow
) > STATUS_BAR_HEIGHT
+
236 SCROLL_ARROW_HEIGHT
*
238 FRONT_PAGE_HEADER_HEIGHT
+
243 CopyMem (&gScreenDimensions
, ScreenDimensions
, sizeof (EFI_SCREEN_DESCRIPTOR
));
245 return EFI_INVALID_PARAMETER
;
250 gOptionBlockWidth
= (CHAR16
) ((gScreenDimensions
.RightColumn
- gScreenDimensions
.LeftColumn
) / 3);
251 gHelpBlockWidth
= gOptionBlockWidth
;
252 gPromptBlockWidth
= gOptionBlockWidth
;
255 // Initialize the strings for the browser, upon exit of the browser, the strings will be freed
257 InitializeBrowserStrings ();
259 gFunctionKeySetting
= DEFAULT_FUNCTION_KEY_SETTING
;
260 gClassOfVfr
= EFI_SETUP_APPLICATION_SUBCLASS
;
261 gResetRequired
= FALSE
;
262 gExitRequired
= FALSE
;
263 gSaveRequired
= FALSE
;
264 gNvUpdateRequired
= FALSE
;
268 BackupHandle
= *Handle
;
269 gMenuRefreshHead
= NULL
;
270 ASSERT (CallbackData
);
271 ZeroMem (CallbackData
, 0x10000);
274 // We can recurse through this and might need to re-allocate this particular buffer
276 if (gPreviousValue
== NULL
) {
277 gPreviousValue
= AllocatePool (0x1000);
278 ASSERT (gPreviousValue
!= NULL
);
284 if (CallbackHandle
!= NULL
) {
286 // Retrieve the Callback protocol interface
288 Status
= gBS
->HandleProtocol (
290 &gEfiFormCallbackProtocolGuid
,
291 (VOID
**) &FormCallback
294 if (EFI_ERROR (Status
)) {
295 FreePool (CallbackData
);
302 // Initializes all the internal state structures for all IFR images in system
304 Status
= InitializeBinaryStructures (Handle
, UseDatabase
, Packet
, NvMapOverride
, HandleCount
, &FileFormTagsHead
);
306 if (EFI_ERROR (Status
)) {
307 FreePool (CallbackData
);
311 // Beginning of the Presentation of the Data
313 if (UseDatabase
&& (HandleCount
> 1)) {
314 Selection
= DisplayHomePage (HandleCount
, FileFormTagsHead
, CallbackData
);
317 // If passing something specific, we know there is only one Ifr
319 Selection
= AllocateZeroPool (sizeof (UI_MENU_OPTION
));
320 ASSERT (Selection
!= NULL
);
321 Selection
->IfrNumber
= 0;
322 Selection
->Handle
= Handle
[0];
328 if (UseDatabase
&& (HandleCount
> 1)) {
329 if (Selection
== NULL
) {
330 FreePool (CallbackData
);
335 // Launch the setup browser with the user's selection information
337 AltSelection
= SetupBrowser (Selection
, Callback
, FileFormTagsHead
, CallbackData
);
340 // If the caller cares about Reset status, we can return to the caller if something happened that required a reset
342 if (ResetRequired
!= NULL
) {
343 *ResetRequired
= gResetRequired
;
346 if (Callback
&& (AltSelection
!= NULL
)) {
347 if ((FormCallback
!= NULL
) && (FormCallback
->Callback
!= NULL
)) {
348 Status
= FormCallback
->Callback (
350 AltSelection
->ThisTag
->Key
,
352 (EFI_HII_CALLBACK_PACKET
**) &Packet
357 *Handle
= BackupHandle
;
359 if (EFI_ERROR (Status
)) {
360 FreePool (CallbackData
);
364 if (Callback
&& (AltSelection
== NULL
)) {
365 FreePool (CallbackData
);
369 if (UseDatabase
&& (HandleCount
> 1)) {
372 if (gBinaryDataHead
->UnRegisterOnExit
) {
373 Hii
->RemovePack (Hii
, Handle
[0]);
377 ((AltSelection
->ThisTag
->SubClass
== EFI_FRONT_PAGE_SUBCLASS
) ||
378 (AltSelection
->ThisTag
->SubClass
== EFI_SINGLE_USE_SUBCLASS
))) {
380 // If this is the FrontPage, return after every selection
382 FreePool (Selection
);
386 // Clean up the allocated data buffers
388 FreeData (FileFormTagsHead
, NULL
, NULL
);
390 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
391 gST
->ConOut
->ClearScreen (gST
->ConOut
);
393 FreePool (CallbackData
);
397 FreePool (Selection
);
401 // Clean up the allocated data buffers
403 FreeData (FileFormTagsHead
, NULL
, NULL
);
405 gST
->ConOut
->ClearScreen (gST
->ConOut
);
408 FreePool (CallbackData
);
413 } while (!EFI_ERROR (Status
));
415 FreePool (CallbackData
);
422 IN EFI_HANDLE ImageHandle
,
423 IN EFI_SYSTEM_TABLE
*SystemTable
431 (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
434 EFI_SUCCESS - Setup loaded.
440 EFI_FORM_CONFIGURATION_DATA
*FormData
;
441 EFI_FORM_BROWSER_PROTOCOL
*FormBrowser
;
443 EFI_HII_PACKAGES
*PackageList
;
446 // There will be only one FormConfig in the system
447 // If there is another out there, someone is trying to install us
448 // again. Fail that scenario.
450 Status
= gBS
->LocateProtocol (
451 &gEfiFormBrowserProtocolGuid
,
453 (VOID
**) &FormBrowser
459 // If there was no error, assume there is an installation and fail to load
461 if (!EFI_ERROR (Status
)) {
462 return EFI_DEVICE_ERROR
;
465 FormData
= AllocatePool (sizeof (EFI_FORM_CONFIGURATION_DATA
));
467 if (FormData
== NULL
) {
468 return EFI_OUT_OF_RESOURCES
;
473 FormData
->Signature
= EFI_FORM_DATA_SIGNATURE
;
474 FormData
->FormConfig
.SendForm
= SendForm
;
475 FormData
->FormConfig
.CreatePopUp
= CreateDialog
;
478 // There should only be one HII image
480 Status
= gBS
->LocateProtocol (
481 &gEfiHiiProtocolGuid
,
483 (VOID
**) &FormData
->Hii
486 ASSERT_EFI_ERROR (Status
);
490 PackageList
= PreparePackages (1, &gEfiFormBrowserProtocolGuid
, SetupBrowserStrings
);
492 Status
= Hii
->NewPack (Hii
, PackageList
, &gHiiHandle
);
494 FreePool (PackageList
);
497 // Install protocol interface
500 Status
= gBS
->InstallProtocolInterface (
502 &gEfiFormBrowserProtocolGuid
,
503 EFI_NATIVE_INTERFACE
,
504 &FormData
->FormConfig
507 ASSERT_EFI_ERROR (Status
);
509 BannerData
= AllocateZeroPool (sizeof (BANNER_DATA
));
510 ASSERT (BannerData
!= NULL
);
512 Status
= InstallPrint ();
519 IN UINT8
*RawFormSet
,
521 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
522 IN UINT16 CurrentVariable
527 Initialize question tag's members.
530 Tag - Pointer of the current EFI_TAG structure.
531 RawFormSet - Pointer of the formset raw data.
532 Index - Offset of the current opcode in the Ifr raw data.
533 FileFormTags - Pointer of current EFI_FILE_FORM_TAGS structure.
534 CurrentVariable - Current variable number.
540 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
542 Tag
->NumberOfLines
= 1;
543 Tag
->VariableNumber
= CurrentVariable
;
544 CopyMem (&Tag
->Id
, &((EFI_IFR_ONE_OF
*) &RawFormSet
[Index
])->QuestionId
, sizeof (UINT16
));
545 CopyMem (&Tag
->StorageStart
, &((EFI_IFR_ONE_OF
*) &RawFormSet
[Index
])->QuestionId
, sizeof (UINT16
));
546 CopyMem (&Tag
->StorageWidth
, &((EFI_IFR_ONE_OF
*) &RawFormSet
[Index
])->Width
, sizeof (UINT8
));
547 CopyMem (&Tag
->Text
, &((EFI_IFR_ONE_OF
*) &RawFormSet
[Index
])->Prompt
, sizeof (UINT16
));
548 CopyMem (&Tag
->Help
, &((EFI_IFR_ONE_OF
*) &RawFormSet
[Index
])->Help
, sizeof (UINT16
));
550 VariableDefinition
= FileFormTags
->VariableDefinitions
;
552 for (; VariableDefinition
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
554 // Have we found the correct variable for the request?
556 if (CurrentVariable
== VariableDefinition
->VariableId
) {
557 if (VariableDefinition
->VariableSize
< (UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
)) {
558 VariableDefinition
->VariableFakeSize
= (UINT16
) (VariableDefinition
->VariableFakeSize
+ Tag
->StorageWidth
);
561 if (VariableDefinition
->NvRamMap
!= NULL
) {
563 // If it is an 8bit or 16bit width, then move it to Tag->Value, otherwise
564 // we will never be looking for the data in Tag->Value (e.g. strings, password, etc)
566 if (Tag
->StorageWidth
== (UINT16
) 1) {
567 CopyMem (&Tag
->Value
, &VariableDefinition
->NvRamMap
[Tag
->StorageStart
], sizeof (UINT16
));
570 if (Tag
->StorageWidth
== (UINT16
) 2) {
573 VariableDefinition
->NvRamMap
[Tag
->StorageStart
] +
574 (VariableDefinition
->NvRamMap
[Tag
->StorageStart
+ 1] * 0x100)
576 CopyMem (&Tag
->Value
, &Index
, sizeof (UINT16
));
580 CopyMem (&Tag
->Value
, &Index
, sizeof (UINT16
));
590 IN UINT8
*RawFormSet
,
592 IN UINT16 NumberOfLines
,
593 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
594 IN UINT16 CurrentVariable
599 Initialize numeric tag's members.
602 Tag - Pointer of the current EFI_TAG structure.
603 RawFormSet - Pointer of the formset raw data.
604 Index - Offset of the current opcode in the Ifr raw data.
605 NumberOfLines - Number of lines this opcode occupied.
606 FileFormTags - Pointer of current EFI_FILE_FORM_TAGS structure.
607 CurrentVariable - Current variable number.
613 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
615 Tag
->NumberOfLines
= NumberOfLines
;
616 Tag
->VariableNumber
= CurrentVariable
;
617 CopyMem (&Tag
->Id
, &((EFI_IFR_ONE_OF
*) &RawFormSet
[Index
])->QuestionId
, sizeof (UINT16
));
618 CopyMem (&Tag
->StorageStart
, &((EFI_IFR_ONE_OF
*) &RawFormSet
[Index
])->QuestionId
, sizeof (UINT16
));
619 CopyMem (&Tag
->StorageWidth
, &((EFI_IFR_ONE_OF
*) &RawFormSet
[Index
])->Width
, sizeof (UINT8
));
620 CopyMem (&Tag
->Text
, &((EFI_IFR_ONE_OF
*) &RawFormSet
[Index
])->Prompt
, sizeof (UINT16
));
621 CopyMem (&Tag
->Help
, &((EFI_IFR_ONE_OF
*) &RawFormSet
[Index
])->Help
, sizeof (UINT16
));
622 CopyMem (&Tag
->Minimum
, &((EFI_IFR_NUMERIC
*) &RawFormSet
[Index
])->Minimum
, sizeof (UINT16
));
623 CopyMem (&Tag
->Maximum
, &((EFI_IFR_NUMERIC
*) &RawFormSet
[Index
])->Maximum
, sizeof (UINT16
));
624 CopyMem (&Tag
->Step
, &((EFI_IFR_NUMERIC
*) &RawFormSet
[Index
])->Step
, sizeof (UINT16
));
625 CopyMem (&Tag
->Default
, &((EFI_IFR_NUMERIC
*) &RawFormSet
[Index
])->Default
, sizeof (UINT16
));
626 Tag
->ResetRequired
= (BOOLEAN
) (((EFI_IFR_NUMERIC
*) &RawFormSet
[Index
])->Flags
& EFI_IFR_FLAG_RESET_REQUIRED
);
628 VariableDefinition
= FileFormTags
->VariableDefinitions
;
630 for (; VariableDefinition
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
632 // Have we found the correct variable for the request?
634 if (CurrentVariable
== VariableDefinition
->VariableId
) {
635 if (VariableDefinition
->VariableSize
<= (UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
)) {
636 if (Tag
->StorageWidth
== 0) {
637 VariableDefinition
->VariableFakeSize
= (UINT16
) (VariableDefinition
->VariableFakeSize
+ 2);
639 VariableDefinition
->VariableFakeSize
= (UINT16
) (VariableDefinition
->VariableFakeSize
+ Tag
->StorageWidth
);
643 if (VariableDefinition
->NvRamMap
!= NULL
) {
645 // If it is an 8bit or 16bit width, then move it to Tag->Value, otherwise
646 // we will never be looking for the data in Tag->Value (e.g. strings, password, etc)
648 if (Tag
->StorageWidth
== (UINT16
) 1) {
649 CopyMem (&Tag
->Value
, &VariableDefinition
->NvRamMap
[Tag
->StorageStart
], sizeof (UINT16
));
652 if (Tag
->StorageWidth
== (UINT16
) 2) {
655 VariableDefinition
->NvRamMap
[Tag
->StorageStart
] +
656 (VariableDefinition
->NvRamMap
[Tag
->StorageStart
+ 1] * 0x100)
658 CopyMem (&Tag
->Value
, &Index
, sizeof (UINT16
));
661 CopyMem (&Tag
->Value
, &Tag
->Default
, sizeof (UINT16
));
670 IN UINT8
*RawFormSet
,
671 IN OUT UINT16
*NumberOfTags
677 // Assume on entry we are pointing to an OpCode - reasonably this should
678 // be a FormOp since the purpose is to count the tags in a particular Form.
680 for (Index
= 0; RawFormSet
[Index
] != EFI_IFR_END_FORM_OP
;) {
682 // If we encounter the end of a form set, bail out
684 if (RawFormSet
[Index
] == EFI_IFR_END_FORM_SET_OP
) {
688 // We treat date/time internally as three op-codes
690 if (RawFormSet
[Index
] == EFI_IFR_DATE_OP
|| RawFormSet
[Index
] == EFI_IFR_TIME_OP
) {
691 *NumberOfTags
= (UINT16
) (*NumberOfTags
+ 3);
694 // Assume that we could have no more tags than op-codes
699 Index
= (UINT16
) (Index
+ RawFormSet
[Index
+ 1]);
702 // Increase the tag count by one so it is inclusive of the end_form_op
709 AddNextInconsistentTag (
710 IN OUT EFI_INCONSISTENCY_DATA
**InconsistentTagsPtr
715 Initialize the next inconsistent tag data and add it to the inconsistent tag list.
718 InconsistentTagsPtr - Pointer of the inconsistent tag's pointer.
725 EFI_INCONSISTENCY_DATA
*PreviousInconsistentTags
;
726 EFI_INCONSISTENCY_DATA
*InconsistentTags
;
728 InconsistentTags
= *InconsistentTagsPtr
;
730 // We just hit the end of an inconsistent expression. Let's allocate the ->Next structure
732 InconsistentTags
->Next
= AllocatePool (sizeof (EFI_INCONSISTENCY_DATA
));
733 ASSERT (InconsistentTags
->Next
!= NULL
);
736 // Preserve current Tag entry
738 PreviousInconsistentTags
= InconsistentTags
;
740 InconsistentTags
= InconsistentTags
->Next
;
743 // This will zero on the entry including the ->Next so I don't have to do it
745 ZeroMem (InconsistentTags
, sizeof (EFI_INCONSISTENCY_DATA
));
748 // Point our Previous field to the previous entry
750 InconsistentTags
->Previous
= PreviousInconsistentTags
;
752 *InconsistentTagsPtr
= InconsistentTags
;
759 InitializeTagStructures (
760 IN EFI_IFR_BINARY
*BinaryData
,
761 OUT EFI_FILE_FORM_TAGS
*FileFormTags
767 UINT16 QuestionIndex
;
771 EFI_FORM_TAGS
*FormTags
;
772 EFI_FORM_TAGS
*SavedFormTags
;
773 EFI_INCONSISTENCY_DATA
*InconsistentTags
;
774 EFI_VARIABLE_DEFINITION
*VariableDefinitions
;
779 UINT16 CurrentVariable
;
780 UINT16 CurrentVariable2
;
783 // Initialize some Index variable and Status
789 CurrentVariable2
= 0;
792 Status
= EFI_SUCCESS
;
793 FormTags
= &FileFormTags
->FormTags
;
794 FormTags
->Next
= NULL
;
795 if (FileFormTags
->InconsistentTags
== NULL
) {
796 InconsistentTags
= NULL
;
798 InconsistentTags
= FileFormTags
->InconsistentTags
;
801 if (FileFormTags
->VariableDefinitions
== NULL
) {
802 VariableDefinitions
= NULL
;
804 VariableDefinitions
= FileFormTags
->VariableDefinitions
;
807 // RawFormSet now points to the beginning of the forms portion of
808 // the specific IFR Binary.
810 RawFormSet
= (UINT8
*) BinaryData
->FormBinary
;
813 // Determine the number of tags for the first form
815 GetTagCount (&RawFormSet
[0], &NumberOfTags
);
817 SavedFormTags
= FormTags
;
819 if (FormTags
->Tags
!= NULL
) {
822 // Advance FormTags to the last entry
824 for (; FormTags
->Next
!= NULL
; FormTags
= FormTags
->Next
)
828 // Walk through each of the tags and free the IntList allocation
830 for (Index
= 0; Index
< NumberOfTags
; Index
++) {
831 if (FormTags
->Tags
[Index
].IntList
!= NULL
) {
832 FreePool (FormTags
->Tags
[Index
].IntList
);
836 FreePool (FormTags
->Tags
);
838 ASSERT (FormTags
->Next
== NULL
);
840 FormTags
->Tags
= NULL
;
842 FormTags
= SavedFormTags
;
844 } while (FormTags
->Next
!= NULL
);
850 // Test for an allocated buffer. If already allocated this is due to having called this routine
851 // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
852 // the tag structure with current values from the NV
854 if (FormTags
->Tags
== NULL
) {
856 // Allocate memory for our tags on the first form
858 FormTags
->Tags
= AllocateZeroPool (NumberOfTags
* sizeof (EFI_TAG
));
859 ASSERT (FormTags
->Tags
);
862 // Test for an allocated buffer. If already allocated this is due to having called this routine
863 // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
864 // the tag structure with current values from the NV
866 if (InconsistentTags
== NULL
) {
868 // We just hit the end of an inconsistent expression. Let's allocate the ->Next structure
870 InconsistentTags
= AllocateZeroPool (sizeof (EFI_INCONSISTENCY_DATA
));
871 ASSERT (InconsistentTags
!= NULL
);
873 FileFormTags
->InconsistentTags
= InconsistentTags
;
876 ZeroMem (FormTags
->Tags
, NumberOfTags
* sizeof (EFI_TAG
));
878 for (CurrTag
= 0; RawFormSet
[Index
] != EFI_IFR_END_FORM_SET_OP
; CurrTag
++) {
880 // Operand = IFR OpCode
882 FormTags
->Tags
[CurrTag
].Operand
= RawFormSet
[Index
];
885 // Assume for now 0 lines occupied by this OpCode
887 FormTags
->Tags
[CurrTag
].NumberOfLines
= 0;
889 FormTags
->Tags
[CurrTag
].Class
= Class
;
890 FormTags
->Tags
[CurrTag
].SubClass
= SubClass
;
893 // Determine the length of the Tag so we can later skip to the next tag in the form
895 TagLength
= RawFormSet
[Index
+ 1];
899 // Operate on the Found OpCode
901 switch (RawFormSet
[Index
]) {
903 case EFI_IFR_FORM_OP
:
905 // If there was no variable op-code defined, create a dummy entry for one
907 if (FileFormTags
->VariableDefinitions
== NULL
) {
908 FileFormTags
->VariableDefinitions
= AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION
));
909 ASSERT (FileFormTags
->VariableDefinitions
!= NULL
);
912 &FormTags
->Tags
[CurrTag
],
913 (VOID
*) &RawFormSet
[Index
],
914 FileFormTags
->VariableDefinitions
917 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
921 case EFI_IFR_SUBTITLE_OP
:
922 case EFI_IFR_TEXT_OP
:
924 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
927 case EFI_IFR_VARSTORE_OP
:
928 if (FileFormTags
->VariableDefinitions
== NULL
) {
929 VariableDefinitions
= AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION
));
930 ASSERT (VariableDefinitions
!= NULL
);
931 FileFormTags
->VariableDefinitions
= VariableDefinitions
;
936 &FormTags
->Tags
[CurrTag
],
937 (VOID
*) &RawFormSet
[Index
],
938 FileFormTags
->VariableDefinitions
942 case EFI_IFR_VARSTORE_SELECT_OP
:
943 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
944 CopyMem (&CurrentVariable
, &((EFI_IFR_VARSTORE_SELECT
*) &RawFormSet
[Index
])->VarId
, sizeof (UINT16
));
945 CurrentVariable2
= CurrentVariable
;
948 case EFI_IFR_VARSTORE_SELECT_PAIR_OP
:
949 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
950 CopyMem(&CurrentVariable
, &((EFI_IFR_VARSTORE_SELECT_PAIR
*)&RawFormSet
[Index
])->VarId
, sizeof (UINT16
));
953 &((EFI_IFR_VARSTORE_SELECT_PAIR
*) &RawFormSet
[Index
])->SecondaryVarId
,
958 case EFI_IFR_END_FORM_OP
:
960 // Test for an allocated buffer. If already allocated this is due to having called this routine
961 // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
962 // the tag structure with current values from the NV
964 if (FormTags
->Next
== NULL
) {
966 // We just hit the end of a form. Let's allocate the ->Next structure
968 FormTags
->Next
= AllocatePool (sizeof (EFI_FORM_TAGS
));
969 ASSERT (FormTags
->Next
);
972 FormTags
= FormTags
->Next
;
973 ZeroMem (FormTags
, sizeof (EFI_FORM_TAGS
));
976 // Reset the tag count to one
981 // Reset the CurrTag value (it will be incremented, after this case statement
982 // so set to a negative one so that we get the desired effect.) Fish can beat me later.
987 // Determine the number of tags after this form. If this is the last
988 // form, then we will count the endformset and preserve that information
989 // in the tag structure.
991 GetTagCount (&RawFormSet
[Index
+ TagLength
], &NumberOfTags
);
994 // Allocate memory for our tags
996 FormTags
->Tags
= AllocateZeroPool (NumberOfTags
* sizeof (EFI_TAG
));
997 ASSERT (FormTags
->Tags
);
1001 // Two types of tags constitute the One Of question: a one-of header and
1002 // several one-of options.
1004 case EFI_IFR_ONE_OF_OP
:
1005 case EFI_IFR_ORDERED_LIST_OP
:
1006 GetQuestionHeader (&FormTags
->Tags
[CurrTag
], RawFormSet
, Index
, FileFormTags
, CurrentVariable
);
1009 // Store away the CurrTag since what follows will be the answer that we
1010 // need to place into the appropriate location in the tag array
1013 // record for setting default later
1015 QuestionIndex
= (UINT16
) CurrTag
;
1018 case EFI_IFR_ONE_OF_OPTION_OP
:
1019 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
1020 FormTags
->Tags
[QuestionIndex
].Flags
= ((EFI_IFR_ONE_OF_OPTION
*) &RawFormSet
[Index
])->Flags
;
1022 &FormTags
->Tags
[QuestionIndex
].Key
,
1023 &((EFI_IFR_ONE_OF_OPTION
*) &RawFormSet
[Index
])->Key
,
1026 FormTags
->Tags
[QuestionIndex
].ResetRequired
= (BOOLEAN
) (FormTags
->Tags
[QuestionIndex
].Flags
& EFI_IFR_FLAG_RESET_REQUIRED
);
1029 case EFI_IFR_CHECKBOX_OP
:
1030 GetQuestionHeader (&FormTags
->Tags
[CurrTag
], RawFormSet
, Index
, FileFormTags
, CurrentVariable
);
1031 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
1034 case EFI_IFR_NUMERIC_OP
:
1035 GetNumericHeader (&FormTags
->Tags
[CurrTag
], RawFormSet
, Index
, (UINT16
) 1, FileFormTags
, CurrentVariable
);
1036 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
1039 case EFI_IFR_DATE_OP
:
1041 // Date elements come in as a Year, Month, Day. We need to process them as a country-based
1042 // Order. It is much easier to do it here than anywhere else.
1044 // For US standards - we want Month/Day/Year, thus we advance "Index" +1, +2, +0 while CurrTag is +0, +1, +2
1047 &FormTags
->Tags
[CurrTag
],
1049 (UINT16
) (Index
+ TagLength
),
1056 // The current language selected + the Date operand
1058 FormTags
->Tags
[CurrTag
+ 1].Operand
= RawFormSet
[Index
];
1060 &FormTags
->Tags
[CurrTag
+ 1],
1062 (UINT16
) (Index
+ TagLength
+ RawFormSet
[Index
+ TagLength
+ 1]),
1069 // The current language selected + the Date operand
1071 FormTags
->Tags
[CurrTag
+ 2].Operand
= RawFormSet
[Index
];
1072 GetNumericHeader (&FormTags
->Tags
[CurrTag
+ 2], RawFormSet
, Index
, (UINT16
) 1, FileFormTags
, CurrentVariable
);
1074 CurrTag
= (INT16
) (CurrTag
+ 2);
1076 Index
= (UINT16
) (Index
+ TagLength
);
1080 TagLength
= RawFormSet
[Index
+ 1];
1081 Index
= (UINT16
) (Index
+ TagLength
);
1085 TagLength
= RawFormSet
[Index
+ 1];
1088 case EFI_IFR_TIME_OP
:
1089 GetNumericHeader (&FormTags
->Tags
[CurrTag
], RawFormSet
, Index
, (UINT16
) 0, FileFormTags
, CurrentVariable
);
1093 // Override the GetQuestionHeader information - date/time are treated very differently
1095 FormTags
->Tags
[CurrTag
].NumberOfLines
= 1;
1099 // The premise is that every date/time op-code have 3 elements, the first 2 have 0 lines
1100 // associated with them, and the third has 1 line to allow to space beyond the choice.
1106 case EFI_IFR_PASSWORD_OP
:
1107 case EFI_IFR_STRING_OP
:
1108 GetQuestionHeader (&FormTags
->Tags
[CurrTag
], RawFormSet
, Index
, FileFormTags
, CurrentVariable
);
1109 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
1112 case EFI_IFR_SUPPRESS_IF_OP
:
1113 case EFI_IFR_GRAYOUT_IF_OP
:
1114 InconsistentTags
->Operand
= ((EFI_IFR_INCONSISTENT
*) &RawFormSet
[Index
])->Header
.OpCode
;
1118 // Since this op-code doesn't use the next field(s), initialize them with something invalid.
1119 // Unfortunately 0 is a valid offset value for a QuestionId
1121 InconsistentTags
->QuestionId1
= INVALID_OFFSET_VALUE
;
1122 InconsistentTags
->QuestionId2
= INVALID_OFFSET_VALUE
;
1125 // Test for an allocated buffer. If already allocated this is due to having called this routine
1126 // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
1127 // the tag structure with current values from the NV
1129 if (InconsistentTags
->Next
== NULL
) {
1130 AddNextInconsistentTag (&InconsistentTags
);
1134 InconsistentTags
= InconsistentTags
->Next
;
1137 case EFI_IFR_FORM_SET_OP
:
1139 &FormTags
->Tags
[CurrTag
].GuidValue
,
1140 &((EFI_IFR_FORM_SET
*) &RawFormSet
[Index
])->Guid
,
1144 &FormTags
->Tags
[CurrTag
].CallbackHandle
,
1145 &((EFI_IFR_FORM_SET
*) &RawFormSet
[Index
])->CallbackHandle
,
1146 sizeof (EFI_PHYSICAL_ADDRESS
)
1148 CopyMem (&FormTags
->Tags
[CurrTag
].Class
, &((EFI_IFR_FORM_SET
*) &RawFormSet
[Index
])->Class
, sizeof (UINT8
));
1150 &FormTags
->Tags
[CurrTag
].SubClass
,
1151 &((EFI_IFR_FORM_SET
*) &RawFormSet
[Index
])->SubClass
,
1155 &FormTags
->Tags
[CurrTag
].NvDataSize
,
1156 &((EFI_IFR_FORM_SET
*) &RawFormSet
[Index
])->NvDataSize
,
1159 Class
= ((EFI_IFR_FORM_SET
*) &RawFormSet
[Index
])->Class
;
1160 SubClass
= ((EFI_IFR_FORM_SET
*) &RawFormSet
[Index
])->SubClass
;
1162 // If the formset has a size value, that means someone must be using this, so create a variable
1163 // We also shall reserve the formid of 0 for this specific purpose.
1165 if ((FileFormTags
->VariableDefinitions
== NULL
) && (FormTags
->Tags
[CurrTag
].NvDataSize
> 0)) {
1166 FileFormTags
->VariableDefinitions
= AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION
));
1167 ASSERT (FileFormTags
->VariableDefinitions
!= NULL
);
1170 &FormTags
->Tags
[CurrTag
],
1171 (VOID
*) &RawFormSet
[Index
],
1172 FileFormTags
->VariableDefinitions
1175 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
1179 case EFI_IFR_BANNER_OP
:
1180 if (gClassOfVfr
== EFI_FRONT_PAGE_SUBCLASS
) {
1182 CopyMem (&TempValue
, &((EFI_IFR_BANNER
*) &RawFormSet
[Index
])->Alignment
, sizeof (UINT8
));
1184 // If this is the special timeout value, we will dynamically figure out where to put it
1185 // Also the least significant byte refers to the TimeOut desired.
1187 if (TempValue
== EFI_IFR_BANNER_TIMEOUT
) {
1188 CopyMem (&FrontPageTimeOutTitle
, &((EFI_IFR_BANNER
*) &RawFormSet
[Index
])->Title
, sizeof (UINT16
));
1189 if (FrontPageTimeOutValue
!= (INT16
) -1) {
1190 CopyMem (&FrontPageTimeOutValue
, &((EFI_IFR_BANNER
*) &RawFormSet
[Index
])->LineNumber
, sizeof (UINT16
));
1196 &BannerData
->Banner
[((EFI_IFR_BANNER
*) &RawFormSet
[Index
])->LineNumber
][
1197 ((EFI_IFR_BANNER
*) &RawFormSet
[Index
])->Alignment
],
1198 &((EFI_IFR_BANNER
*) &RawFormSet
[Index
])->Title
,
1204 case EFI_IFR_INCONSISTENT_IF_OP
:
1206 &FormTags
->Tags
[CurrTag
].Text
,
1207 &((EFI_IFR_INCONSISTENT
*) &RawFormSet
[Index
])->Popup
,
1212 InconsistentTags
->Operand
= ((EFI_IFR_INCONSISTENT
*) &RawFormSet
[Index
])->Header
.OpCode
;
1213 CopyMem (&InconsistentTags
->Popup
, &((EFI_IFR_INCONSISTENT
*) &RawFormSet
[Index
])->Popup
, sizeof (UINT16
));
1216 // Since this op-code doesn't use the next field(s), initialize them with something invalid.
1217 // Unfortunately 0 is a valid offset value for a QuestionId
1219 InconsistentTags
->QuestionId1
= INVALID_OFFSET_VALUE
;
1220 InconsistentTags
->QuestionId2
= INVALID_OFFSET_VALUE
;
1222 InconsistentTags
->VariableNumber
= CurrentVariable
;
1225 // Test for an allocated buffer. If already allocated this is due to having called this routine
1226 // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
1227 // the tag structure with current values from the NV
1229 if (InconsistentTags
->Next
== NULL
) {
1230 AddNextInconsistentTag (&InconsistentTags
);
1234 InconsistentTags
= InconsistentTags
->Next
;
1237 case EFI_IFR_EQ_ID_VAL_OP
:
1238 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
1240 InconsistentTags
->Operand
= ((EFI_IFR_EQ_ID_VAL
*) &RawFormSet
[Index
])->Header
.OpCode
;
1241 CopyMem (&InconsistentTags
->Value
, &((EFI_IFR_EQ_ID_VAL
*) &RawFormSet
[Index
])->Value
, sizeof (UINT16
));
1243 &InconsistentTags
->QuestionId1
,
1244 &((EFI_IFR_EQ_ID_VAL
*) &RawFormSet
[Index
])->QuestionId
,
1249 // Since this op-code doesn't use the next field(s), initialize them with something invalid.
1250 // Unfortunately 0 is a valid offset value for a QuestionId
1252 InconsistentTags
->Width
= FormTags
->Tags
[CurrTag
].StorageWidth
;
1253 InconsistentTags
->QuestionId2
= INVALID_OFFSET_VALUE
;
1254 InconsistentTags
->ConsistencyId
= gConsistencyId
;
1255 FormTags
->Tags
[CurrTag
].ConsistencyId
= gConsistencyId
;
1257 InconsistentTags
->VariableNumber
= CurrentVariable
;
1260 // Test for an allocated buffer. If already allocated this is due to having called this routine
1261 // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
1262 // the tag structure with current values from the NV
1264 if (InconsistentTags
->Next
== NULL
) {
1265 AddNextInconsistentTag (&InconsistentTags
);
1269 InconsistentTags
= InconsistentTags
->Next
;
1272 case EFI_IFR_EQ_VAR_VAL_OP
:
1273 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
1275 InconsistentTags
->Operand
= ((EFI_IFR_EQ_VAR_VAL
*) &RawFormSet
[Index
])->Header
.OpCode
;
1276 CopyMem (&InconsistentTags
->Value
, &((EFI_IFR_EQ_VAR_VAL
*) &RawFormSet
[Index
])->Value
, sizeof (UINT16
));
1278 &InconsistentTags
->QuestionId1
,
1279 &((EFI_IFR_EQ_VAR_VAL
*) &RawFormSet
[Index
])->VariableId
,
1284 // Since this op-code doesn't use the next field(s), initialize them with something invalid.
1285 // Unfortunately 0 is a valid offset value for a QuestionId
1287 InconsistentTags
->QuestionId2
= INVALID_OFFSET_VALUE
;
1288 InconsistentTags
->ConsistencyId
= gConsistencyId
;
1289 FormTags
->Tags
[CurrTag
].ConsistencyId
= gConsistencyId
;
1291 InconsistentTags
->VariableNumber
= CurrentVariable
;
1294 // Test for an allocated buffer. If already allocated this is due to having called this routine
1295 // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
1296 // the tag structure with current values from the NV
1298 if (InconsistentTags
->Next
== NULL
) {
1299 AddNextInconsistentTag (&InconsistentTags
);
1303 InconsistentTags
= InconsistentTags
->Next
;
1306 case EFI_IFR_EQ_ID_ID_OP
:
1307 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
1309 InconsistentTags
->Operand
= ((EFI_IFR_EQ_ID_ID
*) &RawFormSet
[Index
])->Header
.OpCode
;
1311 &InconsistentTags
->QuestionId1
,
1312 &((EFI_IFR_EQ_ID_ID
*) &RawFormSet
[Index
])->QuestionId1
,
1316 &InconsistentTags
->QuestionId2
,
1317 &((EFI_IFR_EQ_ID_ID
*) &RawFormSet
[Index
])->QuestionId2
,
1321 InconsistentTags
->Width
= FormTags
->Tags
[CurrTag
].StorageWidth
;
1322 InconsistentTags
->ConsistencyId
= gConsistencyId
;
1323 FormTags
->Tags
[CurrTag
].ConsistencyId
= gConsistencyId
;
1325 InconsistentTags
->VariableNumber
= CurrentVariable
;
1326 InconsistentTags
->VariableNumber2
= CurrentVariable2
;
1329 // Test for an allocated buffer. If already allocated this is due to having called this routine
1330 // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
1331 // the tag structure with current values from the NV
1333 if (InconsistentTags
->Next
== NULL
) {
1334 AddNextInconsistentTag (&InconsistentTags
);
1338 InconsistentTags
= InconsistentTags
->Next
;
1341 case EFI_IFR_AND_OP
:
1343 case EFI_IFR_NOT_OP
:
1346 case EFI_IFR_TRUE_OP
:
1347 case EFI_IFR_FALSE_OP
:
1348 InconsistentTags
->Operand
= ((EFI_IFR_NOT
*) &RawFormSet
[Index
])->Header
.OpCode
;
1351 // Since this op-code doesn't use the next field(s), initialize them with something invalid.
1352 // Unfortunately 0 is a valid offset value for a QuestionId
1356 // Reserve INVALID_OFFSET_VALUE - 1 for TRUE or FALSE because they are inconsistency tags also, but
1357 // have no coresponding id. The examination of id is needed by evaluating boolean expression.
1359 if (RawFormSet
[Index
] == EFI_IFR_TRUE_OP
||
1360 RawFormSet
[Index
] == EFI_IFR_FALSE_OP
) {
1361 InconsistentTags
->QuestionId1
= INVALID_OFFSET_VALUE
- 1;
1363 InconsistentTags
->QuestionId1
= INVALID_OFFSET_VALUE
;
1365 InconsistentTags
->QuestionId2
= INVALID_OFFSET_VALUE
;
1366 InconsistentTags
->ConsistencyId
= gConsistencyId
;
1367 FormTags
->Tags
[CurrTag
].ConsistencyId
= gConsistencyId
;
1370 // Test for an allocated buffer. If already allocated this is due to having called this routine
1371 // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
1372 // the tag structure with current values from the NV
1374 if (InconsistentTags
->Next
== NULL
) {
1375 AddNextInconsistentTag (&InconsistentTags
);
1379 InconsistentTags
= InconsistentTags
->Next
;
1382 case EFI_IFR_EQ_ID_LIST_OP
:
1383 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
1385 InconsistentTags
->Operand
= ((EFI_IFR_EQ_ID_LIST
*) &RawFormSet
[Index
])->Header
.OpCode
;
1387 &InconsistentTags
->QuestionId1
,
1388 &((EFI_IFR_EQ_ID_LIST
*) &RawFormSet
[Index
])->QuestionId
,
1392 &InconsistentTags
->ListLength
,
1393 &((EFI_IFR_EQ_ID_LIST
*) &RawFormSet
[Index
])->ListLength
,
1396 InconsistentTags
->ValueList
= FormTags
->Tags
[CurrTag
].IntList
;
1399 // Since this op-code doesn't use the next field(s), initialize them with something invalid.
1400 // Unfortunately 0 is a valid offset value for a QuestionId
1402 InconsistentTags
->Width
= FormTags
->Tags
[CurrTag
].StorageWidth
;
1403 InconsistentTags
->QuestionId2
= INVALID_OFFSET_VALUE
;
1404 InconsistentTags
->ConsistencyId
= gConsistencyId
;
1405 FormTags
->Tags
[CurrTag
].ConsistencyId
= gConsistencyId
;
1408 // Test for an allocated buffer. If already allocated this is due to having called this routine
1409 // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
1410 // the tag structure with current values from the NV
1412 if (InconsistentTags
->Next
== NULL
) {
1413 AddNextInconsistentTag (&InconsistentTags
);
1417 InconsistentTags
= InconsistentTags
->Next
;
1420 case EFI_IFR_END_IF_OP
:
1421 InconsistentTags
->Operand
= ((EFI_IFR_END_EXPR
*) &RawFormSet
[Index
])->Header
.OpCode
;
1424 // Since this op-code doesn't use the next field(s), initialize them with something invalid.
1425 // Unfortunately 0 is a valid offset value for a QuestionId
1427 InconsistentTags
->QuestionId1
= INVALID_OFFSET_VALUE
;
1428 InconsistentTags
->QuestionId2
= INVALID_OFFSET_VALUE
;
1431 // Test for an allocated buffer. If already allocated this is due to having called this routine
1432 // once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
1433 // the tag structure with current values from the NV
1435 if (InconsistentTags
->Next
== NULL
) {
1436 AddNextInconsistentTag (&InconsistentTags
);
1440 InconsistentTags
= InconsistentTags
->Next
;
1443 case EFI_IFR_END_ONE_OF_OP
:
1452 // Per spec., we ignore ops that we don't know how to deal with. Skip to next tag
1454 Index
= (UINT16
) (Index
+ TagLength
);
1459 // When we eventually exit, make sure we mark the last tag with an op-code
1461 FormTags
->Tags
[CurrTag
].Operand
= RawFormSet
[Index
];
1463 IfrToFormTag (RawFormSet
[Index
], &FormTags
->Tags
[CurrTag
], (VOID
*) &RawFormSet
[Index
], NULL
);
1466 // Place this as an end of the database marker
1468 InconsistentTags
->Operand
= 0xFF;
1471 // This is the Head of the linked list of pages. Each page is an array of tags
1473 FormTags
= &FileFormTags
->FormTags
;
1474 InconsistentTags
= FileFormTags
->InconsistentTags
;
1476 for (; InconsistentTags
->Operand
!= 0xFF;) {
1477 if (InconsistentTags
->QuestionId1
!= INVALID_OFFSET_VALUE
) {
1479 // Search the tags for the tag which corresponds to this ID
1481 for (CurrTag
= 0; FormTags
->Tags
[0].Operand
!= EFI_IFR_END_FORM_SET_OP
; CurrTag
++) {
1483 // If we hit the end of a form, go to the next set of Tags.
1484 // Remember - EndFormSet op-codes sit on their own page after an end form.
1486 if (FormTags
->Tags
[CurrTag
].Operand
== EFI_IFR_END_FORM_OP
) {
1488 // Reset the CurrTag value (it will be incremented, after this case statement
1489 // so set to a negative one so that we get the desired effect.) Fish can beat me later.
1492 FormTags
= FormTags
->Next
;
1496 if (FormTags
->Tags
[CurrTag
].Id
== InconsistentTags
->QuestionId1
) {
1497 FormTags
->Tags
[CurrTag
].Consistency
++;
1502 FormTags
= &FileFormTags
->FormTags
;
1504 if (InconsistentTags
->QuestionId2
!= INVALID_OFFSET_VALUE
) {
1506 // Search the tags for the tag which corresponds to this ID
1508 for (CurrTag
= 0; FormTags
->Tags
[CurrTag
].Operand
!= EFI_IFR_END_FORM_SET_OP
; CurrTag
++) {
1510 // If we hit the end of a form, go to the next set of Tags.
1511 // Remember - EndFormSet op-codes sit on their own page after an end form.
1513 if (FormTags
->Tags
[CurrTag
].Operand
== EFI_IFR_END_FORM_OP
) {
1515 // Reset the CurrTag value (it will be incremented, after this case statement
1516 // so set to a negative one so that we get the desired effect.) Fish can beat me later.
1519 FormTags
= FormTags
->Next
;
1523 if (FormTags
->Tags
[CurrTag
].Id
== InconsistentTags
->QuestionId2
) {
1524 FormTags
->Tags
[CurrTag
].Consistency
++;
1529 InconsistentTags
= InconsistentTags
->Next
;
1540 CHAR16
*HomePageString
;
1541 CHAR16
*HomeEscapeString
;
1544 // Displays the Header and Footer borders
1546 DisplayPageFrame ();
1548 HomePageString
= GetToken (STRING_TOKEN (HOME_PAGE_TITLE
), gHiiHandle
);
1549 HomeEscapeString
= GetToken (STRING_TOKEN (HOME_ESCAPE_STRING
), gHiiHandle
);
1551 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_YELLOW
| EFI_BRIGHT
);
1553 // PrintStringAt ((gScreenDimensions.RightColumn - GetStringWidth(HomePageString)/2)/2, 1, HomePageString);
1556 (gScreenDimensions
.RightColumn
+ gScreenDimensions
.LeftColumn
- GetStringWidth (HomePageString
) / 2) / 2,
1561 gScreenDimensions
.LeftColumn
+ 2,
1562 gScreenDimensions
.BottomRow
- 3,
1563 (CHAR16
*) L
"%c%c%s",
1569 gScreenDimensions
.RightColumn
- (GetStringWidth (HomeEscapeString
) / 2) - 2,
1570 gScreenDimensions
.BottomRow
- 3,
1574 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
1575 FreePool (HomeEscapeString
);
1576 FreePool (HomePageString
);
1583 IN STRING_REF Token
,
1584 IN EFI_HII_HANDLE HiiHandle
1588 Routine Description:
1590 Get the string based on the TokenID and HII Handle.
1594 Token - The Token ID.
1595 HiiHandle - Handle of Ifr to be fetched.
1608 // Set default string size assumption at no more than 256 bytes
1610 BufferLength
= 0x100;
1612 Buffer
= AllocateZeroPool (BufferLength
);
1613 ASSERT (Buffer
!= NULL
);
1615 Status
= Hii
->GetString (Hii
, HiiHandle
, Token
, TRUE
, NULL
, &BufferLength
, Buffer
);
1617 if (EFI_ERROR (Status
)) {
1618 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1620 // Free the old pool
1625 // Allocate new pool with correct value
1627 Buffer
= AllocatePool (BufferLength
);
1628 ASSERT (Buffer
!= NULL
);
1630 Status
= Hii
->GetString (Hii
, HiiHandle
, Token
, TRUE
, NULL
, &BufferLength
, Buffer
);
1632 if (!EFI_ERROR (Status
)) {
1637 ASSERT_EFI_ERROR (Status
);
1646 IN UINTN NumberOfIfrImages
,
1647 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
1652 EFI_IFR_BINARY
*IfrBinary
;
1654 EFI_FILE_FORM_TAGS
*FileFormTags
;
1655 EFI_FORM_TAGS LocalTags
;
1657 FileFormTags
= FileFormTagsHead
;
1661 Status
= EFI_SUCCESS
;
1664 // If there are no images
1666 if (NumberOfIfrImages
== 0) {
1667 Status
= EFI_NO_MEDIA
;
1671 // IfrBinary points to the beginning of the Binary data linked-list
1673 IfrBinary
= gBinaryDataHead
;
1676 // Print the entries which were in the default language.
1678 for (Index
= 0; Index
< NumberOfIfrImages
; Index
++) {
1679 LocalTags
= FileFormTags
->FormTags
;
1682 // Populate the Menu
1684 StringPtr
= GetToken (IfrBinary
->TitleToken
, IfrBinary
->Handle
);
1687 // If the default language doesn't exist, don't add a menu option yet
1689 if (StringPtr
[0] != CHAR_NULL
) {
1691 // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do
1692 // it in UiFreeMenu.
1694 UiAddMenuOption (StringPtr
, IfrBinary
->Handle
, LocalTags
.Tags
, IfrBinary
->FormBinary
, Index
);
1697 // Advance to the next HII handle
1699 IfrBinary
= IfrBinary
->Next
;
1700 FileFormTags
= FileFormTags
->NextFile
;
1709 IN UINTN NumberOfIfrImages
,
1710 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
1711 IN UINT8
*CallbackData
1715 UI_MENU_OPTION
*Selection
;
1718 // This prints the basic home page template which the user sees
1722 Status
= PopulateHomePage (NumberOfIfrImages
, FileFormTagsHead
);
1724 if (EFI_ERROR (Status
)) {
1729 Selection
= UiDisplayMenu (FALSE
, FileFormTagsHead
, (EFI_IFR_DATA_ARRAY
*) CallbackData
);
1736 InitializeBinaryStructures (
1737 IN EFI_HII_HANDLE
*Handle
,
1738 IN BOOLEAN UseDatabase
,
1739 IN EFI_IFR_PACKET
*Packet
,
1740 IN UINT8
*NvMapOverride
,
1741 IN UINTN NumberOfIfrImages
,
1742 OUT EFI_FILE_FORM_TAGS
**FileFormTagsHead
1747 EFI_IFR_BINARY
*BinaryData
;
1748 EFI_FILE_FORM_TAGS
*FileFormTags
;
1749 UINTN SizeOfNvStore
;
1750 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
1751 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
1752 EFI_VARIABLE_DEFINITION
*OverrideDefinition
;
1755 EFI_HII_VARIABLE_PACK_LIST
*NvMapListHead
;
1756 EFI_HII_VARIABLE_PACK_LIST
*NvMapListNode
;
1759 // Initialize some variables to avoid warnings
1762 *FileFormTagsHead
= NULL
;
1763 FileFormTags
= NULL
;
1764 gBinaryDataHead
= NULL
;
1765 Status
= EFI_SUCCESS
;
1766 FormCallback
= NULL
;
1770 if (NumberOfIfrImages
> 1) {
1771 NvMapOverride
= NULL
;
1774 for (HandleIndex
= 0; HandleIndex
< NumberOfIfrImages
; HandleIndex
+= 1) {
1776 // If the buffers are uninitialized, allocate them, otherwise work on the ->Next members
1778 if ((BinaryData
== NULL
) || (FileFormTags
== NULL
)) {
1780 // Allocate memory for our Binary Data
1782 BinaryData
= AllocateZeroPool (sizeof (EFI_IFR_BINARY
));
1783 ASSERT (BinaryData
);
1786 // Preserve the Head of what will be a linked-list.
1788 gBinaryDataHead
= BinaryData
;
1789 gBinaryDataHead
->Next
= NULL
;
1792 Status
= GetIfrBinaryData (Hii
, Handle
[HandleIndex
], NULL
, BinaryData
);
1794 Status
= GetIfrBinaryData (Hii
, Handle
[HandleIndex
], Packet
, BinaryData
);
1797 // Allocate memory for our File Form Tags
1799 FileFormTags
= AllocateZeroPool (sizeof (EFI_FILE_FORM_TAGS
));
1800 ASSERT (FileFormTags
);
1803 // Preserve the Head of what will be a linked-list.
1805 *FileFormTagsHead
= FileFormTags
;
1806 (*FileFormTagsHead
)->NextFile
= NULL
;
1810 // Allocate memory for our Binary Data linked-list
1811 // Each handle represents a Binary and we will store that data away.
1813 BinaryData
->Next
= AllocateZeroPool (sizeof (EFI_IFR_BINARY
));
1814 ASSERT (BinaryData
->Next
);
1816 BinaryData
= BinaryData
->Next
;
1817 BinaryData
->Next
= NULL
;
1820 Status
= GetIfrBinaryData (Hii
, Handle
[HandleIndex
], NULL
, BinaryData
);
1822 Status
= GetIfrBinaryData (Hii
, Handle
[HandleIndex
], Packet
, BinaryData
);
1825 if (EFI_ERROR (Status
)) {
1826 return EFI_DEVICE_ERROR
;
1829 // Allocate memory for our FileFormTags linked-list
1830 // Each allocation reserves handle represents a Binary and we will store that data away.
1832 FileFormTags
->NextFile
= AllocateZeroPool (sizeof (EFI_FILE_FORM_TAGS
));
1833 ASSERT (FileFormTags
->NextFile
);
1835 FileFormTags
= FileFormTags
->NextFile
;
1840 // Tag Structure Initialization
1842 Status
= InitializeTagStructures (BinaryData
, FileFormTags
);
1844 VariableDefinition
= FileFormTags
->VariableDefinitions
;
1847 // Allocate memory for our NVRAM Maps for all of our variables
1849 for (; VariableDefinition
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
1851 // Pad the fake variable size accordingly - this value should reflect the size of information that is not accounted by
1852 // the mainstream NVRAM variable such as DATE/TIME information that the browser needs to track but is saved to an RTC
1854 VariableDefinition
->VariableFakeSize
= (UINT16
) (VariableDefinition
->VariableSize
+ VariableDefinition
->VariableFakeSize
);
1857 // In the case where a file has no "real" NV data, we should pad the buffer accordingly
1859 if (VariableDefinition
->VariableSize
== 0) {
1860 if (VariableDefinition
->VariableFakeSize
!= 0) {
1861 VariableDefinition
->NvRamMap
= AllocateZeroPool (VariableDefinition
->VariableFakeSize
);
1862 ASSERT (VariableDefinition
->NvRamMap
!= NULL
);
1865 VariableDefinition
->NvRamMap
= AllocateZeroPool (VariableDefinition
->VariableSize
);
1866 ASSERT (VariableDefinition
->NvRamMap
!= NULL
);
1869 if (VariableDefinition
->VariableFakeSize
!= 0) {
1870 VariableDefinition
->FakeNvRamMap
= AllocateZeroPool (VariableDefinition
->VariableFakeSize
);
1871 ASSERT (VariableDefinition
->FakeNvRamMap
!= NULL
);
1875 Status
= gBS
->HandleProtocol (
1876 (VOID
*) (UINTN
) FileFormTags
->FormTags
.Tags
[0].CallbackHandle
,
1877 &gEfiFormCallbackProtocolGuid
,
1878 (VOID
**) &FormCallback
1882 // Since we might have multiple variables, if there is an NvMapOverride we need to use the EFI_VARIABLE_DEFINITION
1883 // information as the information that we pass back and forth. NOTE that callbacks that are initiated will only have the
1884 // NVRAM data refreshed based on the op-code that initiated the callback. In other words, we will pass to the caller a single
1885 // NVRAM map for a single variable based on the op-code that the user selected.
1887 if (NvMapOverride
!= NULL
) {
1888 VariableDefinition
= FileFormTags
->VariableDefinitions
;
1889 OverrideDefinition
= ((EFI_VARIABLE_DEFINITION
*) NvMapOverride
);
1892 // Search through the variable definitions. There should be sufficient passed in settings for the variable op-codes specified
1894 for (; VariableDefinition
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
1895 if ((!CompareMem (VariableDefinition
->VariableName
, L
"Setup", 10)) && (VariableDefinition
->Next
== NULL
)) {
1896 if (VariableDefinition
->VariableSize
!= 0) {
1897 CopyMem (VariableDefinition
->NvRamMap
, NvMapOverride
, VariableDefinition
->VariableSize
);
1899 CopyMem (VariableDefinition
->NvRamMap
, NvMapOverride
, VariableDefinition
->VariableFakeSize
);
1903 VariableDefinition
->NvRamMap
= OverrideDefinition
->NvRamMap
;
1906 // There should NEVER be a ->Next for VariableDefinition and a NULL ->Next for the OverrideDefinition
1908 ASSERT (OverrideDefinition
->Next
);
1909 OverrideDefinition
= OverrideDefinition
->Next
;
1912 VariableDefinition
= FileFormTags
->VariableDefinitions
;
1915 // Search through the variable definitions. There should be sufficient passed in settings for the variable op-codes specified
1917 for (; VariableDefinition
!= NULL
; VariableDefinition
= VariableDefinition
->Next
) {
1918 SizeOfNvStore
= VariableDefinition
->VariableSize
;
1921 // Getting the NvStore and placing it into our Global Data
1923 if ((FormCallback
!= NULL
) && (FormCallback
->NvRead
!= NULL
)) {
1924 Status
= FormCallback
->NvRead (
1926 VariableDefinition
->VariableName
,
1927 &VariableDefinition
->Guid
,
1930 (VOID
*) VariableDefinition
->NvRamMap
1933 Status
= gRT
->GetVariable (
1934 VariableDefinition
->VariableName
,
1935 &VariableDefinition
->Guid
,
1938 (VOID
*) VariableDefinition
->NvRamMap
1942 if (EFI_ERROR (Status
)) {
1944 // If there is a variable that exists already and it is larger than what we calculated the
1945 // storage needs to be, we must assume the variable size from GetVariable is correct and not
1946 // allow the truncation of the variable. It is very possible that the user who created the IFR
1947 // we are cracking is not referring to a variable that was in a previous map, however we cannot
1948 // allow it's truncation.
1950 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1952 // If the buffer was too small, we should have the expanded size requirement in SizeOfNvStore now.
1954 VariableDefinition
->VariableSize
= (UINT16
) SizeOfNvStore
;
1957 // Free the buffer that was allocated that was too small
1959 FreePool (VariableDefinition
->NvRamMap
);
1960 FreePool (VariableDefinition
->FakeNvRamMap
);
1962 VariableDefinition
->NvRamMap
= AllocateZeroPool (SizeOfNvStore
);
1963 VariableDefinition
->FakeNvRamMap
= AllocateZeroPool (SizeOfNvStore
+ VariableDefinition
->VariableFakeSize
);
1964 ASSERT (VariableDefinition
->NvRamMap
);
1965 ASSERT (VariableDefinition
->FakeNvRamMap
);
1967 if ((FormCallback
!= NULL
) && (FormCallback
->NvRead
!= NULL
)) {
1968 Status
= FormCallback
->NvRead (
1970 VariableDefinition
->VariableName
,
1971 &VariableDefinition
->Guid
,
1974 (VOID
*) VariableDefinition
->NvRamMap
1977 Status
= gRT
->GetVariable (
1978 VariableDefinition
->VariableName
,
1979 &VariableDefinition
->Guid
,
1982 (VOID
*) VariableDefinition
->NvRamMap
1987 // if the variable was not found, we will retrieve default values
1989 if (Status
== EFI_NOT_FOUND
) {
1991 if (0 == CompareMem (VariableDefinition
->VariableName
, L
"Setup", 10)) {
1993 NvMapListHead
= NULL
;
1995 Status
= Hii
->GetDefaultImage (Hii
, Handle
[HandleIndex
], EFI_IFR_FLAG_DEFAULT
, &NvMapListHead
);
1997 if (!EFI_ERROR (Status
)) {
1998 ASSERT_EFI_ERROR (NULL
!= NvMapListHead
);
2000 NvMapListNode
= NvMapListHead
;
2002 while (NULL
!= NvMapListNode
) {
2003 if (VariableDefinition
->VariableId
== NvMapListNode
->VariablePack
->VariableId
) {
2004 NvMap
= (VOID
*) ((CHAR8
*) NvMapListNode
->VariablePack
+ sizeof (EFI_HII_VARIABLE_PACK
) + NvMapListNode
->VariablePack
->VariableNameLength
);
2005 NvMapSize
= NvMapListNode
->VariablePack
->Header
.Length
- sizeof (EFI_HII_VARIABLE_PACK
) - NvMapListNode
->VariablePack
->VariableNameLength
;
2008 NvMapListNode
= NvMapListNode
->NextVariablePack
;
2012 // Free the buffer that was allocated.
2014 FreePool (VariableDefinition
->NvRamMap
);
2015 FreePool (VariableDefinition
->FakeNvRamMap
);
2018 // Allocate, copy the NvRamMap.
2020 VariableDefinition
->VariableFakeSize
= (UINT16
) (VariableDefinition
->VariableFakeSize
- VariableDefinition
->VariableSize
);
2021 VariableDefinition
->VariableSize
= (UINT16
) NvMapSize
;
2022 VariableDefinition
->VariableFakeSize
= (UINT16
) (VariableDefinition
->VariableFakeSize
+ VariableDefinition
->VariableSize
);
2024 VariableDefinition
->NvRamMap
= AllocateZeroPool (VariableDefinition
->VariableSize
);
2025 VariableDefinition
->FakeNvRamMap
= AllocateZeroPool (NvMapSize
+ VariableDefinition
->VariableFakeSize
);
2027 CopyMem (VariableDefinition
->NvRamMap
, NvMap
, NvMapSize
);
2028 FreePool (NvMapListHead
);
2032 Status
= EFI_SUCCESS
;
2038 InitializeTagStructures (BinaryData
, FileFormTags
);
2049 IN EFI_HII_PROTOCOL
*Hii
,
2050 IN EFI_HII_HANDLE HiiHandle
,
2051 IN EFI_IFR_PACKET
*Packet
,
2052 IN OUT EFI_IFR_BINARY
*BinaryData
2056 Routine Description:
2057 Fetch the Ifr binary data.
2060 Hii - Point to HII protocol.
2061 HiiHandle - Handle of Ifr to be fetched.
2062 Packet - Pointer to IFR packet.
2063 BinaryData - Buffer to copy the string into
2066 Returns the number of CHAR16 characters that were copied into the OutputString buffer.
2072 EFI_HII_PACKAGES
*PackageList
;
2075 UINT8
*RawFormBinary
;
2076 EFI_IFR_FORM_SET
*FormOp
;
2082 // Initialize the TitleToken to 0 just in case not found
2087 // Try for a 32K Buffer
2089 BufferSize
= 0x8000;
2092 // Allocate memory for our Form binary
2094 Buffer
= AllocateZeroPool (BufferSize
);
2097 if (Packet
== NULL
) {
2098 Status
= Hii
->GetForms (Hii
, HiiHandle
, 0, &BufferSize
, Buffer
);
2100 if (Status
== EFI_BUFFER_TOO_SMALL
) {
2105 // Allocate memory for our Form binary
2107 Buffer
= AllocatePool (BufferSize
);
2110 Status
= Hii
->GetForms (Hii
, HiiHandle
, 0, &BufferSize
, Buffer
);
2114 // Copies the data to local usable buffer
2116 CopyMem (Buffer
, Packet
->IfrData
, Packet
->IfrData
->Header
.Length
);
2119 // Register the string data with HII
2121 PackageList
= PreparePackages (2, NULL
, Packet
->IfrData
, Packet
->StringData
);
2123 Status
= Hii
->NewPack (Hii
, PackageList
, &HiiHandle
);
2125 FreePool (PackageList
);
2128 if (EFI_ERROR (Status
)) {
2132 // We now have the IFR binary in our Buffer
2134 BinaryData
->IfrPackage
= Buffer
;
2135 RawFormBinary
= (UINT8
*) ((CHAR8
*) (Buffer
) + sizeof (EFI_HII_PACK_HEADER
));
2136 BinaryData
->FormBinary
= (UINT8
*) ((CHAR8
*) (Buffer
) + sizeof (EFI_HII_PACK_HEADER
));
2137 BinaryData
->Handle
= HiiHandle
;
2140 // If a packet was passed in, remove the string data when exiting.
2142 if (Packet
!= NULL
) {
2143 BinaryData
->UnRegisterOnExit
= TRUE
;
2145 BinaryData
->UnRegisterOnExit
= FALSE
;
2148 // Walk through the FormSet Opcodes looking for the FormSet opcode
2149 // If we hit EFI_IFR_END_SET_OP we know we hit the end of the FormSet.
2151 for (Index
= 0; RawFormBinary
[Index
] != EFI_IFR_END_FORM_SET_OP
;) {
2152 FormOp
= (EFI_IFR_FORM_SET
*) &RawFormBinary
[Index
];
2153 Index
= (UINT16
) (Index
+ FormOp
->Header
.Length
);
2155 if (FormOp
->Header
.OpCode
== EFI_IFR_FORM_SET_OP
) {
2156 TitleToken
= FormOp
->FormSetTitle
;
2158 // If displaying FrontPage - set the flag signifying it
2160 switch (FormOp
->SubClass
) {
2161 case EFI_FRONT_PAGE_SUBCLASS
:
2162 FrontPageHandle
= HiiHandle
;
2165 gClassOfVfr
= FormOp
->SubClass
;
2168 // Match GUID to find out the function key setting. If match fail, use the default setting.
2170 for (Index2
= 0; Index2
< sizeof (gFunctionKeySettingTable
) / sizeof (FUNCTIION_KEY_SETTING
); Index2
++) {
2171 if (CompareGuid ((EFI_GUID
*)(UINTN
)&FormOp
->Guid
, &(gFunctionKeySettingTable
[Index2
].FormSetGuid
))) {
2173 // Update the function key setting.
2175 gFunctionKeySetting
= gFunctionKeySettingTable
[Index2
].KeySetting
;
2177 // Function key prompt can not be displayed if the function key has been disabled.
2179 if ((gFunctionKeySetting
& FUNCTION_ONE
) != FUNCTION_ONE
) {
2180 gFunctionOneString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2183 if ((gFunctionKeySetting
& FUNCTION_TWO
) != FUNCTION_TWO
) {
2184 gFunctionTwoString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2187 if ((gFunctionKeySetting
& FUNCTION_NINE
) != FUNCTION_NINE
) {
2188 gFunctionNineString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2191 if ((gFunctionKeySetting
& FUNCTION_TEN
) != FUNCTION_TEN
) {
2192 gFunctionTenString
= GetToken (STRING_TOKEN (EMPTY_STRING
), gHiiHandle
);
2199 BinaryData
->TitleToken
= TitleToken
;
2204 EFI_HANDLE PrintHandle
= NULL
;
2205 EFI_PRINT_PROTOCOL mPrintProtocol
= { UnicodeVSPrint
};
2213 return gBS
->InstallProtocolInterface (
2215 &gEfiPrintProtocolGuid
,
2216 EFI_NATIVE_INTERFACE
,