2 Implementation for handling the User Interface option processing.
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.
19 ExtractRequestedNvMap (
20 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
22 OUT EFI_VARIABLE_DEFINITION
**VariableDefinition
25 *VariableDefinition
= FileFormTags
->VariableDefinitions
;
28 // Extract the data from the NV variable - consumer will free the buffer.
30 for (; *VariableDefinition
!= NULL
; *VariableDefinition
= (*VariableDefinition
)->Next
) {
32 // If there is a variable with this ID return with EFI_SUCCESS
34 if (!CompareMem (&(*VariableDefinition
)->VariableId
, &VariableId
, sizeof (UINT16
))) {
44 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
46 IN UINT16 VariableSize
,
47 IN UINT16 OffsetValue
,
52 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
54 Status
= ExtractRequestedNvMap (FileFormTags
, VariableId
, &VariableDefinition
);
56 if (!EFI_ERROR (Status
)) {
58 // Allocate sufficient space for the data and copy it into the outgoing buffer
60 if (VariableSize
!= 0) {
61 *Buffer
= AllocateZeroPool (VariableSize
);
62 ASSERT (*Buffer
!= NULL
);
63 CopyMem (*Buffer
, &VariableDefinition
->NvRamMap
[OffsetValue
], VariableSize
);
74 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
75 IN UI_MENU_OPTION
*MenuOption
82 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
86 SizeRequired
= MenuOption
->ThisTag
->StorageStart
+ MenuOption
->ThisTag
->StorageWidth
;
88 ExtractRequestedNvMap (FileFormTags
, MenuOption
->Tags
->VariableNumber
, &VariableDefinition
);
91 // We arrived here because the current NvRamMap is too small for the new op-code to store things and
92 // we need to adjust the buffer to support this.
94 NvRamMap
= AllocateZeroPool (SizeRequired
+ 1);
95 ASSERT (NvRamMap
!= NULL
);
98 // Copy current NvRamMap to the new NvRamMap
100 CopyMem (NvRamMap
, VariableDefinition
->NvRamMap
, VariableDefinition
->VariableFakeSize
);
103 // Remember, the only time we come here is because we are in the NVPlus section of the NvRamMap
105 for (Index
= MenuOption
->TagIndex
;
106 (MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_FORM_OP
) && (MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
);
110 switch (MenuOption
->Tags
[Index
].Operand
) {
111 case EFI_IFR_ORDERED_LIST_OP
:
112 case EFI_IFR_ONE_OF_OP
:
113 CachedStart
= MenuOption
->Tags
[Index
].StorageStart
;
116 case EFI_IFR_ONE_OF_OPTION_OP
:
117 if (MenuOption
->Tags
[Index
].Flags
& EFI_IFR_FLAG_DEFAULT
) {
118 CopyMem (&NvRamMap
[CachedStart
], &MenuOption
->Tags
[Index
].Value
, 2);
122 case EFI_IFR_CHECKBOX_OP
:
123 CopyMem (&NvRamMap
[MenuOption
->Tags
[Index
].StorageStart
], &MenuOption
->Tags
[Index
].Flags
, 1);
126 case EFI_IFR_NUMERIC_OP
:
127 case EFI_IFR_DATE_OP
:
128 case EFI_IFR_TIME_OP
:
129 case EFI_IFR_STRING_OP
:
130 case EFI_IFR_PASSWORD_OP
:
132 &NvRamMap
[MenuOption
->Tags
[Index
].StorageStart
],
133 &MenuOption
->Tags
[Index
].Value
,
134 MenuOption
->Tags
[Index
].StorageWidth
141 gBS
->FreePool (VariableDefinition
->NvRamMap
);
142 VariableDefinition
->NvRamMap
= NvRamMap
;
143 VariableDefinition
->VariableFakeSize
= (UINT16
) SizeRequired
;
148 IN UI_MENU_OPTION
*MenuOption
,
150 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
151 IN EFI_IFR_DATA_ARRAY
*PageData
,
152 OUT CHAR16
**OptionString
159 EFI_FILE_FORM_TAGS
*FileFormTags
;
161 CHAR16 FormattedNumber
[6];
172 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
174 CHAR16 NullCharacter
;
176 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
182 FileFormTags
= FileFormTagsHead
;
184 for (Index
= 0; Index
< MenuOption
->IfrNumber
; Index
++) {
185 FileFormTags
= FileFormTags
->NextFile
;
191 VariableDefinition
= NULL
;
194 ZeroMem (&Time
, sizeof (EFI_TIME
));
196 StringPtr
= (CHAR16
*) L
"\0";
197 Tag
= MenuOption
->ThisTag
;
198 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
200 if (Tag
->StorageStart
> VariableDefinition
->VariableSize
) {
201 NvRamMap
= (UINT16
*) &VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
];
203 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
210 NullCharacter
= CHAR_NULL
;
213 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
215 if (((UINT8
*) NvRamMap
)[0] != 0x00) {
220 ZeroMem (FormattedNumber
, 12);
222 Status
= gBS
->HandleProtocol (
223 (VOID
*) (UINTN
) FileFormTags
->FormTags
.Tags
[0].CallbackHandle
,
224 &gEfiFormCallbackProtocolGuid
,
225 (VOID
**) &FormCallback
228 if (*OptionString
!= NULL
) {
229 gBS
->FreePool (*OptionString
);
230 *OptionString
= NULL
;
233 switch (Tag
->Operand
) {
235 case EFI_IFR_ORDERED_LIST_OP
:
236 case EFI_IFR_ONE_OF_OP
:
238 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
239 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
240 // the NvMap so that we can properly display the information
242 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
243 AdjustNvMap (FileFormTags
, MenuOption
);
244 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
247 CachedIndex
= MenuOption
->TagIndex
;
250 // search for EFI_IFR_ONE_OF_OPTION_OP until you hit the EFI_IFR_END_ONE_OF_OP,
251 // each of the .Text in the options are going to be what gets displayed. Break each into 26 char chunks
252 // when hit right/left arrow allows for selection - then repopulate Tag[TagIndex] with the choice
254 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
; Index
++) {
256 // We found an option - which assumedly has a string. We will eventually have to support
257 // wrapping of strings. For now, let's pretend they don't wrap and code that up.
259 // Count how many strings there are
261 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
263 // If one of the options for the one-of has an interactive flag, back-define the oneof to have one too
265 if (MenuOption
->Tags
[Index
].Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
266 MenuOption
->Tags
[CachedIndex
].Flags
= (UINT8
) (MenuOption
->Tags
[CachedIndex
].Flags
| EFI_IFR_FLAG_INTERACTIVE
);
273 // We now know how many strings we will have, so we can allocate the
274 // space required for the array or strings.
276 *OptionString
= AllocateZeroPool (StringCount
* (gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
277 ASSERT (*OptionString
);
280 // Add left delimeter to string
282 *OptionString
[0] = LEFT_ONEOF_DELIMITER
;
285 // Retrieve the current OneOf value
289 // Auto selection from list
293 // Copy current setting to the seed Value
295 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
296 ValueArray
= AllocateZeroPool (MenuOption
->ThisTag
->StorageWidth
);
297 ASSERT (ValueArray
!= NULL
);
298 CopyMem (ValueArray
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
300 CopyMem (&Value
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
301 CopyMem (gPreviousValue
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
305 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
306 Status
= GetSelectionInputPopUp (MenuOption
, Tag
, MenuOption
->ThisTag
->StorageWidth
, ValueArray
, &KeyValue
);
308 Status
= GetSelectionInputPopUp (MenuOption
, Tag
, 1, &Value
, &KeyValue
);
311 if (!EFI_ERROR (Status
)) {
312 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
313 CopyMem (NvRamMap
, ValueArray
, MenuOption
->ThisTag
->StorageWidth
);
314 gBS
->FreePool (ValueArray
);
317 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
319 CopyMem (NvRamMap
, &Value
, Tag
->StorageWidth
);
320 MenuOption
->ThisTag
->Key
= KeyValue
;
323 // If a late check is required save off the information. This is used when consistency checks
324 // are required, but certain values might be bound by an impossible consistency check such as
325 // if two questions are bound by consistency checks and each only has two possible choices, there
326 // would be no way for a user to switch the values. Thus we require late checking.
328 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
329 CopyMem (&Tag
->OldValue
, &Value
, Tag
->StorageWidth
);
332 // In theory, passing the value and the Id are sufficient to determine what needs
333 // to be done. The Id is the key to look for the entry needed in the Inconsistency
334 // database. That will yields operand and ID data - and since the ID's correspond
335 // to the NV storage, we can determine the values for other IDs there.
337 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
338 if (PopUp
== 0x0000) {
342 if (!Tag
->Suppress
&& !Tag
->GrayOut
) {
343 CopyMem (NvRamMap
, &Number
, MenuOption
->ThisTag
->StorageWidth
);
348 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
350 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
353 Status
= WaitForKeyStroke (&Key
);
355 switch (Key
.UnicodeChar
) {
357 case CHAR_CARRIAGE_RETURN
:
359 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
361 CopyMem (NvRamMap
, &Number
, MenuOption
->ThisTag
->StorageWidth
);
362 gBS
->FreePool (StringPtr
);
368 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
372 UpdateStatusBar (NV_UPDATE_REQUIRED
, Tag
->Flags
, TRUE
);
374 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
375 gBS
->FreePool (ValueArray
);
381 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
; Index
++) {
383 // We found an option - which assumedly has a string. We will eventually have to support
384 // wrapping of strings. For now, let's pretend they don't wrap and code that up.
386 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
390 // If the first entry is invalid, then the "default" settings are based on what is reflected
391 // in the order of the op-codes
393 ((UINT8
*) NvRamMap
)[Index
- MenuOption
->TagIndex
- 1] = (UINT8
) MenuOption
->Tags
[Index
].Value
;
396 // Only display 3 lines of stuff at most
398 if ((Index
- MenuOption
->TagIndex
) > ORDERED_LIST_SIZE
) {
402 if (((Index
- MenuOption
->TagIndex
) != 1) && !Skip
) {
403 Character
[0] = LEFT_ONEOF_DELIMITER
;
404 NewStrCat (OptionString
[0], Character
);
407 MenuOption
->ThisTag
->NumberOfLines
= (UINT16
) (Index
- MenuOption
->TagIndex
);
409 StringPtr
= GetToken (MenuOption
->Tags
[Index
].Text
, MenuOption
->Handle
);
411 for (Value
= (UINT16
) (MenuOption
->TagIndex
+ 1);
412 MenuOption
->Tags
[Value
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
415 if (MenuOption
->Tags
[Value
].Value
== ((UINT8
*) NvRamMap
)[Index
- MenuOption
->TagIndex
- 1]) {
416 StringPtr
= GetToken (MenuOption
->Tags
[Value
].Text
, MenuOption
->Handle
);
421 if (MenuOption
->Tags
[Value
].Operand
== EFI_IFR_END_ONE_OF_OP
) {
428 NewStrCat (OptionString
[0], StringPtr
);
429 Character
[0] = RIGHT_ONEOF_DELIMITER
;
430 NewStrCat (OptionString
[0], Character
);
431 Character
[0] = CHAR_CARRIAGE_RETURN
;
432 NewStrCat (OptionString
[0], Character
);
435 // Remove Buffer allocated for StringPtr after it has been used.
437 gBS
->FreePool (StringPtr
);
440 // The option value is the same as what is stored in NV store. Print this.
442 if (!CompareMem (&(MenuOption
->Tags
[Index
].Value
), NvRamMap
, MenuOption
->ThisTag
->StorageWidth
)) {
443 StringPtr
= GetToken (MenuOption
->Tags
[Index
].Text
, MenuOption
->Handle
);
444 NewStrCat (OptionString
[0], StringPtr
);
445 Character
[0] = RIGHT_ONEOF_DELIMITER
;
446 NewStrCat (OptionString
[0], Character
);
448 // Remove Buffer allocated for StringPtr after it has been used.
450 gBS
->FreePool (StringPtr
);
455 if ((MenuOption
->Tags
[Index
].Flags
& EFI_IFR_FLAG_DEFAULT
) == 1) {
456 Default
= MenuOption
->Tags
[Index
].Text
;
457 Value
= MenuOption
->Tags
[Index
].Value
;
463 // We didn't find a value that matched a setting in the NVRAM Map - display default - set default
467 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
469 CopyMem (NvRamMap
, &Value
, MenuOption
->ThisTag
->StorageWidth
);
471 StringPtr
= GetToken ((UINT16
) Default
, MenuOption
->Handle
);
472 NewStrCat (OptionString
[0], StringPtr
);
473 Character
[0] = RIGHT_ONEOF_DELIMITER
;
474 NewStrCat (OptionString
[0], Character
);
476 // Remove Buffer allocated for StringPtr after it has been used.
478 gBS
->FreePool (StringPtr
);
483 case EFI_IFR_CHECKBOX_OP
:
485 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
486 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
487 // the NvMap so that we can properly display the information
489 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
490 AdjustNvMap (FileFormTags
, MenuOption
);
491 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
494 Default
= Tag
->Flags
& 1;
496 // If hit spacebar, set or unset Tag[TagIndex].Flags based on it's previous value - BOOLEAN
498 *OptionString
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
499 ASSERT (*OptionString
);
502 // Since Checkboxes are BOOLEAN values, bit 0 of the Flags bit defines the default option, therefore, if
503 // the default option (only one option for checkboxes) is on, then the default value is on. Tag.Default is not
504 // an active field for Checkboxes.
506 StrnCpy (OptionString
[0], (CHAR16
*) LEFT_CHECKBOX_DELIMITER
, 1);
509 // Since this is a BOOLEAN operation, flip bit 0 upon selection
512 Tag
->Value
= (UINT16
) (Tag
->Value
^ 1);
513 *(UINT8
*) NvRamMap
= (UINT8
) (Tag
->Value
& 1);
514 UpdateStatusBar (NV_UPDATE_REQUIRED
, Tag
->Flags
, TRUE
);
517 if ((*(UINT8
*) NvRamMap
& 1) == 0x01) {
518 NewStrCat (OptionString
[0], (CHAR16
*) CHECK_ON
);
520 // If someone reset default variables - we may need to reload from our NvMapping....
522 Tag
->Value
= *(UINT8
*) NvRamMap
;
525 // If someone reset default variables - we may need to reload from our NvMapping....
527 NewStrCat (OptionString
[0], (CHAR16
*) CHECK_OFF
);
528 Tag
->Value
= *(UINT8
*) NvRamMap
;
531 NewStrCat (OptionString
[0], (CHAR16
*) RIGHT_CHECKBOX_DELIMITER
);
532 NewStrCat (OptionString
[0], StringPtr
);
535 case EFI_IFR_NUMERIC_OP
:
537 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
538 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
539 // the NvMap so that we can properly display the information
541 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
542 AdjustNvMap (FileFormTags
, MenuOption
);
543 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
546 *OptionString
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
547 ASSERT (*OptionString
);
550 // Add left delimeter to string
552 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
555 // Retrieve the current numeric value
561 if (Tag
->Step
== 0) {
565 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, TRUE
, Tag
, REGULAR_NUMERIC
, &Number
);
566 if (!EFI_ERROR (Status
)) {
567 CopyMem (gPreviousValue
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
568 UpdateStatusBar (NV_UPDATE_REQUIRED
, Tag
->Flags
, TRUE
);
571 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
573 CopyMem (NvRamMap
, &Number
, MenuOption
->ThisTag
->StorageWidth
);
579 // Auto selection from list
581 if ((((Tag
->StorageWidth
== 1) && (UINT8
) (*NvRamMap
) > Tag
->Maximum
) || ((UINT8
) (*NvRamMap
) < Tag
->Minimum
)) ||
582 (((Tag
->StorageWidth
== 2) && *NvRamMap
> Tag
->Maximum
) || (*NvRamMap
< Tag
->Minimum
))
585 // Seed Number with valid value if currently invalid
587 Number
= Tag
->Default
;
589 if (Tag
->StorageWidth
== 1) {
590 Number
= (UINT8
) (*NvRamMap
);
596 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, FALSE
, Tag
, REGULAR_NUMERIC
, &Number
);
597 if (!EFI_ERROR (Status
)) {
598 CopyMem (gPreviousValue
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
599 UpdateStatusBar (NV_UPDATE_REQUIRED
, Tag
->Flags
, TRUE
);
602 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
604 CopyMem (NvRamMap
, &Number
, MenuOption
->ThisTag
->StorageWidth
);
610 if (((Tag
->StorageWidth
== 1) && (UINT8
) (*NvRamMap
) <= Tag
->Maximum
&& (UINT8
) (*NvRamMap
) >= Tag
->Minimum
) ||
611 ((Tag
->StorageWidth
== 2) && *NvRamMap
<= Tag
->Maximum
&& *NvRamMap
>= Tag
->Minimum
)
613 if (Tag
->StorageWidth
== 1) {
614 Number
= (UINT8
) (*NvRamMap
);
618 UnicodeValueToString (
622 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
624 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
625 StrnCpy (OptionString
[0] + 1, FormattedNumber
, Number
);
628 // If *NvRamMap isn't within parameters, set it to within parameters
631 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
633 CopyMem (NvRamMap
, &Tag
->Default
, MenuOption
->ThisTag
->StorageWidth
);
634 Number
= Tag
->Default
;
636 UnicodeValueToString (
640 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
642 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
643 StrnCpy (OptionString
[0] + 1, FormattedNumber
, Number
);
646 *(OptionString
[0] + Number
/ 2) = RIGHT_NUMERIC_DELIMITER
;
647 NewStrCat (OptionString
[0] + (Number
/ 2) + 1, StringPtr
);
651 case EFI_IFR_DATE_OP
:
653 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
654 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
655 // the NvMap so that we can properly display the information
657 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
658 AdjustNvMap (FileFormTags
, MenuOption
);
659 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
662 Status
= gRT
->GetTime (&Time
, NULL
);
663 if (EFI_ERROR (Status
)) {
667 // This for loop advances Index till it points immediately after a date entry. We can then
668 // subtract MenuOption->TagIndex from Index and find out relative to the start of the Date
669 // structure which field we were in. For instance, if TagIndex was 52, and we advanced Index
670 // to 53 and found it to no longer point to a date operand, we were pointing to the last of 3
674 // This has BUGBUG potential....fix this - if someone wants to ask two DATE questions in a row.....code
675 // against such silliness.
677 // Also, we want to internationalize the order of the date information. We need to code for it as well.
679 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
== EFI_IFR_DATE_OP
; Index
++)
683 // Count 0 = We entered on the first Date operand
684 // Count 1 = We entered on the second Date operand
685 // Count 2 = We entered on the third Date operand
687 Count
= 3 - (Index
- MenuOption
->TagIndex
);
692 // This is similar to numerics, except for the following:
693 // We will under normal circumstances get 3 consecutive calls
694 // to process this opcodes data.
696 *OptionString
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
697 ASSERT (*OptionString
);
702 Number
= (UINT16
) Time
.Month
;
704 if (Tag
->Step
== 0) {
705 MenuOption
->OptCol
++;
706 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, TRUE
, Tag
, DATE_NUMERIC
, &Number
);
709 // Seed value with current setting
711 Tag
->Value
= (UINT16
) Time
.Month
;
712 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, FALSE
, Tag
, DATE_NUMERIC
, &Number
);
715 if (!EFI_ERROR (Status
)) {
716 Time
.Month
= (UINT8
) Number
;
717 gRT
->SetTime (&Time
);
721 VariableDefinition
->FakeNvRamMap
[Tag
->Id
] = Time
.Month
;
722 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
724 UnicodeValueToString (
728 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
730 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
733 FormattedNumber
[2] = FormattedNumber
[1];
734 FormattedNumber
[1] = FormattedNumber
[0];
735 FormattedNumber
[0] = L
'0';
739 StrnCpy (OptionString
[0] + 1, FormattedNumber
, Number
);
740 *(OptionString
[0] + Number
/ 2) = DATE_SEPARATOR
;
741 StrCat (OptionString
[0] + (Number
/ 2) + 1, StringPtr
);
746 Number
= (UINT16
) Time
.Day
;
748 if (Tag
->Step
== 0) {
749 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, TRUE
, Tag
, DATE_NUMERIC
, &Number
);
752 // Seed value with current setting
754 Tag
->Value
= (UINT16
) Time
.Day
;
755 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, FALSE
, Tag
, DATE_NUMERIC
, &Number
);
758 if (!EFI_ERROR (Status
)) {
759 Time
.Day
= (UINT8
) Number
;
760 gRT
->SetTime (&Time
);
764 VariableDefinition
->FakeNvRamMap
[Tag
->Id
] = Time
.Day
;
765 SetUnicodeMem (OptionString
[0], 4, L
' ');
767 UnicodeValueToString (
771 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
773 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
775 FormattedNumber
[2] = FormattedNumber
[1];
776 FormattedNumber
[1] = FormattedNumber
[0];
777 FormattedNumber
[0] = L
'0';
781 StrnCpy (OptionString
[0] + 4, FormattedNumber
, Number
);
782 *(OptionString
[0] + Number
/ 2 + 3) = DATE_SEPARATOR
;
783 StrCat (OptionString
[0] + (Number
/ 2) + 4, StringPtr
);
788 Number
= (UINT16
) Time
.Year
;
790 if (Tag
->Step
== 0) {
791 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, TRUE
, Tag
, DATE_NUMERIC
, &Number
);
794 // Seed value with current setting
796 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, FALSE
, Tag
, DATE_NUMERIC
, &Number
);
799 if (!EFI_ERROR (Status
)) {
800 Time
.Year
= (UINT16
) Number
;
801 gRT
->SetTime (&Time
);
805 Tag
->Value
= (UINT16
) Time
.Year
;
806 VariableDefinition
->FakeNvRamMap
[Tag
->Id
] = (UINT8
) Tag
->Value
;
807 VariableDefinition
->FakeNvRamMap
[Tag
->Id
+ 1] = (UINT8
) (Tag
->Value
>> 8);
808 SetUnicodeMem (OptionString
[0], 7, L
' ');
809 UnicodeValueToString (
813 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
815 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
816 StrnCpy (OptionString
[0] + 7, FormattedNumber
, Number
);
817 *(OptionString
[0] + Number
/ 2 + 6) = RIGHT_NUMERIC_DELIMITER
;
818 StrCat (OptionString
[0] + (Number
/ 2) + 7, StringPtr
);
825 // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
826 // We need to add code to support the NVRam storage version of Date - this is the 1% case where someone
827 // might want to set an alarm and actually preserve the data in NVRam so a driver can pick up the instruction
828 // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
830 case EFI_IFR_TIME_OP
:
832 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
833 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
834 // the NvMap so that we can properly display the information
836 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
837 AdjustNvMap (FileFormTags
, MenuOption
);
838 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
841 Status
= gRT
->GetTime (&Time
, NULL
);
842 if (EFI_ERROR (Status
)) {
846 // This is similar to numerics, except for the following:
847 // We will under normal circumstances get 3 consecutive calls
848 // to process this opcodes data.
850 *OptionString
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
851 ASSERT (*OptionString
);
854 // This for loop advances Index till it points immediately after a date entry. We can then
855 // subtract MenuOption->TagIndex from Index and find out relative to the start of the Date
856 // structure which field we were in. For instance, if TagIndex was 52, and we advanced Index
857 // to 53 and found it to no longer point to a date operand, we were pointing to the last of 3
860 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
== EFI_IFR_TIME_OP
; Index
++)
863 // Count 0 = We entered on the first Date operand
864 // Count 1 = We entered on the second Date operand
865 // Count 2 = We entered on the third Date operand
867 Count
= 3 - (Index
- MenuOption
->TagIndex
);
878 Number
= Time
.Minute
;
882 Number
= Time
.Second
;
885 // Retrieve the current numeric value
891 if (Tag
->Step
== 0) {
895 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, TRUE
, Tag
, TIME_NUMERIC
, &Number
);
896 if (!EFI_ERROR (Status
)) {
899 gRT
->SetTime (&Time
);
905 // Auto selection from list
907 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, FALSE
, Tag
, TIME_NUMERIC
, &Number
);
908 if (!EFI_ERROR (Status
)) {
917 Time
.Hour
= (UINT8
) Number
;
921 Time
.Minute
= (UINT8
) Number
;
925 Time
.Second
= (UINT8
) Number
;
929 gRT
->SetTime (&Time
);
933 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
934 UnicodeValueToString (
938 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
940 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
942 FormattedNumber
[2] = FormattedNumber
[1];
943 FormattedNumber
[1] = FormattedNumber
[0];
944 FormattedNumber
[0] = L
'0';
948 StrnCpy (OptionString
[0] + 1, FormattedNumber
, Number
);
949 *(OptionString
[0] + Number
/ 2) = TIME_SEPARATOR
;
950 StrCat (OptionString
[0] + (Number
/ 2) + 1, StringPtr
);
954 SetUnicodeMem (OptionString
[0], 4, L
' ');
955 UnicodeValueToString (
959 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
961 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
963 FormattedNumber
[2] = FormattedNumber
[1];
964 FormattedNumber
[1] = FormattedNumber
[0];
965 FormattedNumber
[0] = L
'0';
969 StrnCpy (OptionString
[0] + 4, FormattedNumber
, Number
);
970 *(OptionString
[0] + Number
/ 2 + 3) = TIME_SEPARATOR
;
971 StrCat (OptionString
[0] + (Number
/ 2) + 4, StringPtr
);
975 SetUnicodeMem (OptionString
[0], 7, L
' ');
976 UnicodeValueToString (
980 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
982 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
984 FormattedNumber
[2] = FormattedNumber
[1];
985 FormattedNumber
[1] = FormattedNumber
[0];
986 FormattedNumber
[0] = L
'0';
990 StrnCpy (OptionString
[0] + 7, FormattedNumber
, Number
);
991 *(OptionString
[0] + Number
/ 2 + 6) = RIGHT_NUMERIC_DELIMITER
;
992 StrCat (OptionString
[0] + (Number
/ 2) + 7, StringPtr
);
996 // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
997 // We need to add code to support the NVRam storage version of Date - this is the 1% case where someone
998 // might want to set an alarm and actually preserve the data in NVRam so a driver can pick up the instruction
999 // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
1004 case EFI_IFR_STRING_OP
:
1006 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
1007 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
1008 // the NvMap so that we can properly display the information
1010 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
1011 AdjustNvMap (FileFormTags
, MenuOption
);
1012 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
1015 *OptionString
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
1016 ASSERT (*OptionString
);
1019 StringPtr
= AllocateZeroPool (Tag
->Maximum
);
1022 Status
= ReadString (MenuOption
, StringPtr
);
1024 if (!EFI_ERROR (Status
)) {
1025 CopyMem (gPreviousValue
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
1026 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], StringPtr
, Tag
->StorageWidth
);
1028 UpdateStatusBar (NV_UPDATE_REQUIRED
, Tag
->Flags
, TRUE
);
1031 gBS
->FreePool (StringPtr
);
1034 for (Index
= 0; Index
< gOptionBlockWidth
; Index
++) {
1035 if (VariableDefinition
->NvRamMap
[Tag
->StorageStart
+ (Index
* 2)] != 0x0000) {
1036 CopyMem (OptionString
[0] + Index
, &VariableDefinition
->NvRamMap
[Tag
->StorageStart
+ (Index
* 2)], 2);
1039 *(OptionString
[0] + Index
) = '_';
1040 *(OptionString
[0] + 1 + Index
) = 0;
1049 case EFI_IFR_PASSWORD_OP
:
1051 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
1052 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
1053 // the NvMap so that we can properly display the information
1055 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
1056 AdjustNvMap (FileFormTags
, MenuOption
);
1057 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
1061 StringPtr
= AllocateZeroPool (Tag
->Maximum
);
1065 // If interactive, read the password and do the appropriate callbacks in that routine.
1066 // Since interactive passwords assume to handle the password data in a separate variable
1067 // storage, we don't need to do more than what is below for password callbacks
1069 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
1070 MenuOption
->Tags
[0].CallbackHandle
= FileFormTags
->FormTags
.Tags
[0].CallbackHandle
;
1071 Status
= ReadPassword (MenuOption
, TRUE
, Tag
, PageData
, FALSE
, FileFormTags
, StringPtr
);
1072 ZeroMem (StringPtr
, Tag
->Maximum
);
1074 if (EFI_ERROR (Status
)) {
1075 if (Status
== EFI_NOT_READY
) {
1076 gBS
->FreePool (StringPtr
);
1081 Status
= ReadPassword (MenuOption
, TRUE
, Tag
, PageData
, TRUE
, FileFormTags
, StringPtr
);
1082 gBS
->FreePool (StringPtr
);
1086 for (Index
= 0; Index
< Tag
->Maximum
; Index
++) {
1087 if (VariableDefinition
->NvRamMap
[Tag
->StorageStart
+ Index
] != 0x00) {
1089 // There is something there! Prompt for password
1091 Status
= ReadPassword (MenuOption
, TRUE
, Tag
, PageData
, FALSE
, FileFormTags
, StringPtr
);
1092 if (EFI_ERROR (Status
)) {
1093 gBS
->FreePool (StringPtr
);
1097 if (Tag
->Encoding
== 1) {
1098 EncodePassword (StringPtr
, (UINT8
) Tag
->Maximum
);
1099 Status
= CompareMem (StringPtr
, &VariableDefinition
->NvRamMap
[Tag
->StorageStart
], Tag
->Maximum
);
1101 Status
= CompareMem (StringPtr
, &VariableDefinition
->NvRamMap
[Tag
->StorageStart
], Tag
->Maximum
);
1105 gBS
->FreePool (StringPtr
);
1115 ZeroMem (StringPtr
, Tag
->Maximum
);
1118 // No password set! Go ahead and prompt the user for a password.
1120 Status
= ReadPassword (MenuOption
, FALSE
, Tag
, PageData
, FALSE
, FileFormTags
, StringPtr
);
1122 if (EFI_ERROR (Status
)) {
1124 // User couldn't figure out how to type two identical passwords
1126 gBS
->FreePool (StringPtr
);
1130 // Very simple example of how one MIGHT do password encoding
1132 if (Tag
->Encoding
== 1) {
1133 EncodePassword (StringPtr
, (UINT8
) Tag
->Maximum
);
1136 TmpNvRamMap
= AllocatePool (VariableDefinition
->VariableSize
);
1137 ASSERT (TmpNvRamMap
!= NULL
);
1139 Count
= VariableDefinition
->VariableSize
;
1141 if ((FormCallback
!= NULL
) && (FormCallback
->NvRead
!= NULL
)) {
1142 Status
= FormCallback
->NvRead (
1144 VariableDefinition
->VariableName
,
1145 &VariableDefinition
->Guid
,
1148 (VOID
*) TmpNvRamMap
1151 Status
= gRT
->GetVariable (
1152 VariableDefinition
->VariableName
,
1153 &VariableDefinition
->Guid
,
1156 (VOID
*) TmpNvRamMap
1160 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], StringPtr
, Tag
->StorageWidth
);
1161 CopyMem (&TmpNvRamMap
[Tag
->StorageStart
], StringPtr
, Tag
->StorageWidth
);
1163 if ((FormCallback
!= NULL
) && (FormCallback
->NvWrite
!= NULL
)) {
1164 Status
= FormCallback
->NvWrite (
1166 VariableDefinition
->VariableName
,
1167 &VariableDefinition
->Guid
,
1168 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1169 VariableDefinition
->VariableSize
,
1170 (VOID
*) TmpNvRamMap
,
1174 Status
= gRT
->SetVariable (
1175 VariableDefinition
->VariableName
,
1176 &VariableDefinition
->Guid
,
1177 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1178 VariableDefinition
->VariableSize
,
1179 (VOID
*) TmpNvRamMap
1183 gBS
->FreePool (TmpNvRamMap
);
1184 gBS
->FreePool (StringPtr
);
1196 Split StringPtr to several lines of strings stored in FormattedString and the glyph width of
1197 each line cannot exceed gHelpBlockWidth.
1199 @param StringPtr The pointer of string
1200 @param FormattedString The pointer of format string
1201 @param RowCount The count of row
1206 IN CHAR16
*StringPtr
,
1207 OUT CHAR16
**FormattedString
,
1211 CONST UINTN BlockWidth
= (UINTN
) gHelpBlockWidth
- 1;
1214 // [PrevCurrIndex, CurrIndex) forms a range of a screen-line
1217 UINTN PrevCurrIndex
;
1219 UINTN VirtualLineCount
;
1221 // GlyphOffset stores glyph width of current screen-line
1225 // GlyphWidth equals to 2 if we meet width directive
1229 // during scanning, we remember the position of last space character
1230 // in case that if next word cannot put in current line, we could restore back to the position
1231 // of last space character
1232 // while we should also remmeber the glyph width of the last space character for restoring
1234 UINTN LastSpaceIndex
;
1235 UINTN LastSpaceGlyphWidth
;
1237 // every time we begin to form a new screen-line, we should remember glyph width of single character
1240 UINTN LineStartGlyphWidth
;
1242 UINTN
*OldIndexArray
;
1245 // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )
1246 // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want
1247 // to bring the width directive of the last line to current screen-line.
1248 // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line
1249 // different from that of "\wideabcde", we should remember the width directive.
1251 AllocateSize
= 0x20;
1252 IndexArray
= AllocatePool (AllocateSize
* sizeof (UINTN
) * 3);
1254 if (*FormattedString
!= NULL
) {
1255 FreePool (*FormattedString
);
1256 *FormattedString
= NULL
;
1259 for (PrevCurrIndex
= 0, CurrIndex
= 0, LineCount
= 0, LastSpaceIndex
= 0,
1260 IndexArray
[0] = 0, GlyphWidth
= 1, GlyphOffset
= 0, LastSpaceGlyphWidth
= 1, LineStartGlyphWidth
= 1;
1261 (StringPtr
[CurrIndex
] != CHAR_NULL
);
1264 if (LineCount
== AllocateSize
) {
1265 AllocateSize
+= 0x10;
1266 OldIndexArray
= IndexArray
;
1267 IndexArray
= AllocatePool (AllocateSize
* sizeof (UINTN
) * 3);
1268 CopyMem (IndexArray
, OldIndexArray
, LineCount
* sizeof (UINTN
) * 3);
1269 if (OldIndexArray
!= NULL
) {
1270 FreePool (OldIndexArray
);
1274 switch (StringPtr
[CurrIndex
]) {
1278 GlyphWidth
= ((StringPtr
[CurrIndex
] == WIDE_CHAR
) ? 2 : 1);
1279 if (CurrIndex
== 0) {
1280 LineStartGlyphWidth
= GlyphWidth
;
1286 // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN
1290 // Store a range of string as a line
1292 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1293 IndexArray
[LineCount
*3+1] = CurrIndex
;
1294 IndexArray
[LineCount
*3+2] = LineStartGlyphWidth
;
1297 // Reset offset and save begin position of line
1300 LineStartGlyphWidth
= GlyphWidth
;
1301 PrevCurrIndex
= CurrIndex
+ 1;
1306 // "\r\n" and "\r" both are handled here
1308 case CHAR_CARRIAGE_RETURN
:
1309 if (StringPtr
[CurrIndex
+ 1] == CHAR_LINEFEED
) {
1311 // next char is '\n'
1313 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1314 IndexArray
[LineCount
*3+1] = CurrIndex
;
1315 IndexArray
[LineCount
*3+2] = LineStartGlyphWidth
;
1320 LineStartGlyphWidth
= GlyphWidth
;
1321 PrevCurrIndex
= CurrIndex
+ 1;
1325 // char is space or other char
1328 GlyphOffset
+= GlyphWidth
;
1329 if (GlyphOffset
>= BlockWidth
) {
1330 if (LastSpaceIndex
> PrevCurrIndex
) {
1332 // LastSpaceIndex points to space inside current screen-line,
1333 // restore to LastSpaceIndex
1334 // (Otherwise the word is too long to fit one screen-line, just cut it)
1336 CurrIndex
= LastSpaceIndex
;
1337 GlyphWidth
= LastSpaceGlyphWidth
;
1338 } else if (GlyphOffset
> BlockWidth
) {
1340 // the word is too long to fit one screen-line and we don't get the chance
1341 // of GlyphOffset == BlockWidth because GlyphWidth = 2
1346 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1347 IndexArray
[LineCount
*3+1] = CurrIndex
+ 1;
1348 IndexArray
[LineCount
*3+2] = LineStartGlyphWidth
;
1349 LineStartGlyphWidth
= GlyphWidth
;
1352 // Reset offset and save begin position of line
1355 PrevCurrIndex
= CurrIndex
+ 1;
1359 // LastSpaceIndex: remember position of last space
1361 if (StringPtr
[CurrIndex
] == CHAR_SPACE
) {
1362 LastSpaceIndex
= CurrIndex
;
1363 LastSpaceGlyphWidth
= GlyphWidth
;
1369 if (GlyphOffset
> 0) {
1370 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1371 IndexArray
[LineCount
*3+1] = CurrIndex
;
1372 IndexArray
[LineCount
*3+2] = GlyphWidth
;
1376 if (LineCount
== 0) {
1378 // in case we meet null string
1383 // we assume null string's glyph width is 1
1389 VirtualLineCount
= RowCount
* (LineCount
/ RowCount
+ (LineCount
% RowCount
> 0));
1390 *FormattedString
= AllocateZeroPool (VirtualLineCount
* (BlockWidth
+ 1) * sizeof (CHAR16
) * 2);
1392 for (CurrIndex
= 0; CurrIndex
< LineCount
; CurrIndex
++) {
1393 *(*FormattedString
+ CurrIndex
* 2 * (BlockWidth
+ 1)) = (CHAR16
)((IndexArray
[CurrIndex
*3+2] == 2) ? WIDE_CHAR
: NARROW_CHAR
);
1395 *FormattedString
+ CurrIndex
* 2 * (BlockWidth
+ 1) + 1,
1396 StringPtr
+ IndexArray
[CurrIndex
*3],
1397 IndexArray
[CurrIndex
*3+1]-IndexArray
[CurrIndex
*3]
1401 if (IndexArray
!= NULL
) {
1402 FreePool (IndexArray
);
1409 IN EFI_TAG
*TargetTag
,
1411 EFI_VARIABLE_DEFINITION
*VariableDefinitionsHead
1415 CHAR16
*VariableName
;
1417 EFI_VARIABLE_DEFINITION
*VariableDefinitions
;
1418 EFI_VARIABLE_DEFINITION
*PreviousVariableDefinitions
;
1419 STATIC UINT16 VariableSize
;
1421 STATIC UINT16 CurrentVariable
;
1422 STATIC UINT16 CurrentVariable2
;
1426 case EFI_IFR_FORM_OP
:
1427 CopyMem (&TargetTag
->Id
, &((EFI_IFR_FORM
*) FormData
)->FormId
, sizeof (UINT16
));
1428 CopyMem (&TargetTag
->Text
, &((EFI_IFR_FORM
*) FormData
)->FormTitle
, sizeof (UINT16
));
1429 TargetTag
->VariableNumber
= CurrentVariable
;
1430 if (VariableDefinitionsHead
!= NULL
) {
1431 VariableName
= AllocateZeroPool (12);
1432 ASSERT (VariableName
!= NULL
);
1433 CopyMem (VariableName
, L
"Setup", 12);
1434 VariableDefinitionsHead
->VariableName
= VariableName
;
1435 VariableDefinitionsHead
->VariableSize
= VariableSize
;
1436 CopyMem (&VariableDefinitionsHead
->Guid
, &Guid
, sizeof (EFI_GUID
));
1440 case EFI_IFR_SUBTITLE_OP
:
1441 TargetTag
->NumberOfLines
= 1;
1442 CopyMem (&TargetTag
->Text
, &((EFI_IFR_SUBTITLE
*) FormData
)->SubTitle
, sizeof (UINT16
));
1443 TargetTag
->VariableNumber
= CurrentVariable
;
1446 case EFI_IFR_TEXT_OP
:
1447 TargetTag
->NumberOfLines
= 1;
1448 CopyMem (&TargetTag
->Text
, &((EFI_IFR_TEXT
*) FormData
)->Text
, sizeof (UINT16
));
1449 CopyMem (&TargetTag
->Help
, &((EFI_IFR_TEXT
*) FormData
)->Help
, sizeof (UINT16
));
1450 TargetTag
->VariableNumber
= CurrentVariable
;
1453 // To optimize the encoding size, certain opcodes have optional fields such as those
1454 // inside the if() statement. If the encoded length is the complete size, then we
1455 // know we have valid data encoded that we want to integrate
1457 if (((EFI_IFR_TEXT
*) FormData
)->Header
.Length
== sizeof (EFI_IFR_TEXT
)) {
1459 // Text has no help associated with it, but in case there is a second entry due to
1460 // dynamic/interactive flags being active, bring this data over.
1462 CopyMem (&TargetTag
->TextTwo
, &((EFI_IFR_TEXT
*) FormData
)->TextTwo
, sizeof (UINT16
));
1463 TargetTag
->Flags
= ((EFI_IFR_TEXT
*) FormData
)->Flags
;
1464 CopyMem (&TargetTag
->Key
, &((EFI_IFR_TEXT
*) FormData
)->Key
, sizeof (UINT16
));
1468 case EFI_IFR_ONE_OF_OPTION_OP
:
1469 CopyMem (&TargetTag
->Text
, &((EFI_IFR_ONE_OF_OPTION
*) FormData
)->Option
, sizeof (UINT16
));
1470 CopyMem (&TargetTag
->Value
, &((EFI_IFR_ONE_OF_OPTION
*) FormData
)->Value
, sizeof (UINT16
));
1471 TargetTag
->Flags
= ((EFI_IFR_ONE_OF_OPTION
*) FormData
)->Flags
;
1472 CopyMem (&TargetTag
->Key
, &((EFI_IFR_ONE_OF_OPTION
*) FormData
)->Key
, sizeof (UINT16
));
1473 TargetTag
->VariableNumber
= CurrentVariable
;
1476 case EFI_IFR_CHECKBOX_OP
:
1477 TargetTag
->Flags
= ((EFI_IFR_CHECKBOX
*) FormData
)->Flags
;
1478 TargetTag
->ResetRequired
= (BOOLEAN
) (TargetTag
->Flags
& EFI_IFR_FLAG_RESET_REQUIRED
);
1479 CopyMem (&TargetTag
->Key
, &((EFI_IFR_CHECKBOX
*) FormData
)->Key
, sizeof (UINT16
));
1480 TargetTag
->VariableNumber
= CurrentVariable
;
1483 case EFI_IFR_NUMERIC_OP
:
1484 TargetTag
->Flags
= ((EFI_IFR_NUMERIC
*) FormData
)->Flags
;
1485 CopyMem (&TargetTag
->Key
, &((EFI_IFR_NUMERIC
*) FormData
)->Key
, sizeof (UINT16
));
1486 TargetTag
->VariableNumber
= CurrentVariable
;
1489 case EFI_IFR_STRING_OP
:
1491 // Convert EFI_IFR_STRING.MinSize and EFI_IFR_STRING.MaxSize to actual minimum and maximum bytes
1492 // and store to EFI_TAG.Minimum and EFI_TAG.Maximum
1495 CopyMem (&TempValue
, &((EFI_IFR_STRING
*) FormData
)->MinSize
, sizeof (UINT8
));
1496 TempValue
= (UINT16
) (TempValue
* 2);
1497 CopyMem (&TargetTag
->Minimum
, &TempValue
, sizeof (UINT16
));
1500 CopyMem (&TempValue
, &((EFI_IFR_STRING
*) FormData
)->MaxSize
, sizeof (UINT8
));
1501 TempValue
= (UINT16
) (TempValue
* 2);
1502 CopyMem (&TargetTag
->Maximum
, &TempValue
, sizeof (UINT16
));
1503 CopyMem (&TargetTag
->StorageWidth
, &TempValue
, sizeof (UINT16
));
1504 TargetTag
->Flags
= (UINT8
) (((EFI_IFR_STRING
*) FormData
)->Flags
);
1505 TargetTag
->ResetRequired
= (BOOLEAN
) (TargetTag
->Flags
& EFI_IFR_FLAG_RESET_REQUIRED
);
1506 CopyMem (&TargetTag
->Key
, &((EFI_IFR_STRING
*) FormData
)->Key
, sizeof (UINT16
));
1507 TargetTag
->VariableNumber
= CurrentVariable
;
1510 case EFI_IFR_PASSWORD_OP
:
1512 CopyMem (&TempValue
, &((EFI_IFR_PASSWORD
*) FormData
)->MinSize
, sizeof (UINT8
));
1513 TempValue
= (UINT16
) (TempValue
* 2);
1514 CopyMem (&TargetTag
->Minimum
, &TempValue
, sizeof (UINT16
));
1517 CopyMem (&TempValue
, &((EFI_IFR_PASSWORD
*) FormData
)->MaxSize
, sizeof (UINT8
));
1518 TempValue
= (UINT16
) (TempValue
* 2);
1519 CopyMem (&TargetTag
->Maximum
, &TempValue
, sizeof (UINT16
));
1520 CopyMem (&TargetTag
->StorageWidth
, &TempValue
, sizeof (UINT16
));
1521 TargetTag
->Flags
= ((EFI_IFR_PASSWORD
*) FormData
)->Flags
;
1522 TargetTag
->ResetRequired
= (BOOLEAN
) (TargetTag
->Flags
& EFI_IFR_FLAG_RESET_REQUIRED
);
1523 CopyMem (&TargetTag
->Key
, &((EFI_IFR_PASSWORD
*) FormData
)->Key
, sizeof (UINT16
));
1524 CopyMem (&TargetTag
->Encoding
, &((EFI_IFR_PASSWORD
*) FormData
)->Encoding
, sizeof (UINT16
));
1525 TargetTag
->VariableNumber
= CurrentVariable
;
1528 case EFI_IFR_VARSTORE_OP
:
1530 // It should NEVER be NULL
1532 if (VariableDefinitionsHead
== NULL
) {
1536 VariableDefinitions
= VariableDefinitionsHead
;
1539 // Advance VariableDefinitions to the last entry
1541 for (; VariableDefinitions
!= NULL
; VariableDefinitions
= VariableDefinitions
->Next
) {
1542 PreviousVariableDefinitions
= VariableDefinitions
;
1544 // If there is a variable with this GUID and ID already, we need to bail out
1546 if (!CompareMem (&VariableDefinitions
->Guid
, &((EFI_IFR_VARSTORE
*) FormData
)->Guid
, sizeof (EFI_GUID
)) &&
1547 !CompareMem (&VariableDefinitions
->VariableId
, &((EFI_IFR_VARSTORE
*) FormData
)->VarId
, sizeof (UINT16
))
1552 if (VariableDefinitions
->Next
== NULL
) {
1557 // If the last entry has a variable in it already, allocate a new entry and use it
1559 if (VariableDefinitions
->VariableName
!= NULL
) {
1560 VariableDefinitions
->Next
= AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION
));
1561 ASSERT (VariableDefinitions
->Next
!= NULL
);
1562 PreviousVariableDefinitions
= VariableDefinitions
;
1563 VariableDefinitions
= VariableDefinitions
->Next
;
1564 VariableDefinitions
->Previous
= PreviousVariableDefinitions
;
1567 // Copy the Variable data to our linked list
1569 CopyMem (&VariableDefinitions
->VariableId
, &((EFI_IFR_VARSTORE
*) FormData
)->VarId
, sizeof (UINT16
));
1570 CopyMem (&VariableDefinitions
->VariableSize
, &((EFI_IFR_VARSTORE
*) FormData
)->Size
, sizeof (UINT16
));
1571 CopyMem (&VariableDefinitions
->Guid
, &((EFI_IFR_VARSTORE
*) FormData
)->Guid
, sizeof (EFI_GUID
));
1574 // The ASCII String which is immediately past the EFI_IFR_VARSTORE is inferred by the structure definition
1575 // due to it being variable sized. There are rules preventing it from being > 40 characters long and should
1576 // be enforced by the compiler.
1578 AsciiString
= (CHAR8
*) (&((EFI_IFR_VARSTORE
*) FormData
)->Size
);
1579 AsciiString
= AsciiString
+ 2;
1580 VariableDefinitions
->VariableName
= AllocateZeroPool ((AsciiStrLen (AsciiString
) + 1) * 2);
1581 ASSERT (VariableDefinitions
->VariableName
!= NULL
);
1582 for (Index
= 0; AsciiString
[Index
] != 0; Index
++) {
1583 VariableDefinitions
->VariableName
[Index
] = (CHAR16
) AsciiString
[Index
];
1586 VariableDefinitions
->VariableName
[Index
] = 0;
1589 // Propogate the tag information for this op-code
1591 CopyMem (&TargetTag
->VariableNumber
, &((EFI_IFR_VARSTORE
*) FormData
)->VarId
, sizeof (UINT16
));
1592 CopyMem (&TargetTag
->GuidValue
, &((EFI_IFR_VARSTORE
*) FormData
)->Guid
, sizeof (EFI_GUID
));
1593 CopyMem (&TargetTag
->StorageWidth
, &((EFI_IFR_VARSTORE
*) FormData
)->Size
, sizeof (UINT16
));
1594 CopyMem (&TargetTag
->Maximum
, &((EFI_IFR_VARSTORE
*) FormData
)->Size
, sizeof (UINT16
));
1597 case EFI_IFR_VARSTORE_SELECT_OP
:
1598 CopyMem (&TargetTag
->VariableNumber
, &((EFI_IFR_VARSTORE_SELECT
*) FormData
)->VarId
, sizeof (UINT16
));
1599 CopyMem (&CurrentVariable
, &((EFI_IFR_VARSTORE_SELECT
*) FormData
)->VarId
, sizeof (UINT16
));
1600 CurrentVariable2
= CurrentVariable
;
1603 case EFI_IFR_VARSTORE_SELECT_PAIR_OP
:
1604 CopyMem (&TargetTag
->VariableNumber
, &((EFI_IFR_VARSTORE_SELECT_PAIR
*) FormData
)->VarId
, sizeof (UINT16
));
1606 &TargetTag
->VariableNumber2
,
1607 &((EFI_IFR_VARSTORE_SELECT_PAIR
*) FormData
)->SecondaryVarId
,
1610 CopyMem (&CurrentVariable
, &((EFI_IFR_VARSTORE_SELECT_PAIR
*) FormData
)->VarId
, sizeof (UINT16
));
1611 CopyMem (&CurrentVariable2
, &((EFI_IFR_VARSTORE_SELECT_PAIR
*) FormData
)->SecondaryVarId
, sizeof (UINT16
));
1614 case EFI_IFR_REF_OP
:
1615 TargetTag
->NumberOfLines
= 1;
1616 CopyMem (&TargetTag
->Id
, &((EFI_IFR_REF
*) FormData
)->FormId
, sizeof (UINT16
));
1617 CopyMem (&TargetTag
->Key
, &((EFI_IFR_REF
*) FormData
)->Key
, sizeof (UINT16
));
1618 CopyMem (&TargetTag
->Text
, &((EFI_IFR_REF
*) FormData
)->Prompt
, sizeof (UINT16
));
1619 CopyMem (&TargetTag
->Help
, &((EFI_IFR_REF
*) FormData
)->Help
, sizeof (UINT16
));
1620 TargetTag
->Flags
= ((EFI_IFR_REF
*) FormData
)->Flags
;
1621 TargetTag
->VariableNumber
= CurrentVariable
;
1624 case EFI_IFR_EQ_ID_VAL_OP
:
1625 CopyMem (&TargetTag
->Value
, &((EFI_IFR_EQ_ID_VAL
*) FormData
)->Value
, sizeof (UINT16
));
1626 CopyMem (&TargetTag
->Id
, &((EFI_IFR_EQ_ID_VAL
*) FormData
)->QuestionId
, sizeof (UINT16
));
1627 TargetTag
->StorageWidth
= ((EFI_IFR_EQ_ID_VAL
*) FormData
)->Width
;
1628 TargetTag
->VariableNumber
= CurrentVariable
;
1631 case EFI_IFR_EQ_VAR_VAL_OP
:
1632 CopyMem (&TargetTag
->Value
, &((EFI_IFR_EQ_VAR_VAL
*) FormData
)->Value
, sizeof (UINT16
));
1633 CopyMem (&TargetTag
->Id
, &((EFI_IFR_EQ_VAR_VAL
*) FormData
)->VariableId
, sizeof (UINT16
));
1634 TargetTag
->VariableNumber
= CurrentVariable
;
1637 case EFI_IFR_EQ_ID_ID_OP
:
1638 CopyMem (&TargetTag
->Id
, &((EFI_IFR_EQ_ID_ID
*) FormData
)->QuestionId1
, sizeof (UINT16
));
1639 CopyMem (&TargetTag
->Id2
, &((EFI_IFR_EQ_ID_ID
*) FormData
)->QuestionId2
, sizeof (UINT16
));
1640 TargetTag
->StorageWidth
= ((EFI_IFR_EQ_ID_ID
*) FormData
)->Width
;
1641 TargetTag
->VariableNumber
= CurrentVariable
;
1642 TargetTag
->VariableNumber
= CurrentVariable2
;
1645 case EFI_IFR_EQ_ID_LIST_OP
:
1646 CopyMem (&TargetTag
->Id
, &((EFI_IFR_EQ_ID_LIST
*) FormData
)->QuestionId
, sizeof (UINT16
));
1647 CopyMem (&TargetTag
->Id2
, &((EFI_IFR_EQ_ID_LIST
*) FormData
)->ListLength
, sizeof (UINT16
));
1648 TargetTag
->StorageWidth
= ((EFI_IFR_EQ_ID_LIST
*) FormData
)->Width
;
1650 TargetTag
->IntList
= AllocateZeroPool (TargetTag
->Id2
* sizeof (UINT16
));
1651 ASSERT (TargetTag
->IntList
);
1653 for (TempValue
= 0; TempValue
< TargetTag
->Id2
; TempValue
++) {
1655 &TargetTag
->IntList
[TempValue
],
1656 &((EFI_IFR_EQ_ID_LIST
*) FormData
)->ValueList
[TempValue
],
1661 TargetTag
->VariableNumber
= CurrentVariable
;
1664 case EFI_IFR_FORM_SET_OP
:
1665 CopyMem (&VariableSize
, &((EFI_IFR_FORM_SET
*) FormData
)->NvDataSize
, sizeof (UINT16
));
1666 CopyMem (&Guid
, &((EFI_IFR_FORM_SET
*) FormData
)->Guid
, sizeof (EFI_GUID
));
1668 // If there is a size specified in the formste, we will establish a "default" variable
1670 if (VariableDefinitionsHead
!= NULL
) {
1671 VariableName
= AllocateZeroPool (12);
1672 ASSERT (VariableName
!= NULL
);
1673 CopyMem (VariableName
, L
"Setup", 12);
1674 VariableDefinitionsHead
->VariableName
= VariableName
;
1675 VariableDefinitionsHead
->VariableSize
= VariableSize
;
1676 CopyMem (&VariableDefinitionsHead
->Guid
, &Guid
, sizeof (EFI_GUID
));
1680 case EFI_IFR_END_FORM_SET_OP
:
1681 CurrentVariable
= 0;
1682 CurrentVariable2
= 0;