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.
16 // Include common header file for this module.
18 #include "CommonHeader.h"
24 ExtractRequestedNvMap (
25 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
27 OUT EFI_VARIABLE_DEFINITION
**VariableDefinition
30 *VariableDefinition
= FileFormTags
->VariableDefinitions
;
33 // Extract the data from the NV variable - consumer will free the buffer.
35 for (; *VariableDefinition
!= NULL
; *VariableDefinition
= (*VariableDefinition
)->Next
) {
37 // If there is a variable with this ID return with EFI_SUCCESS
39 if (!CompareMem (&(*VariableDefinition
)->VariableId
, &VariableId
, sizeof (UINT16
))) {
49 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
51 IN UINT16 VariableSize
,
52 IN UINT16 OffsetValue
,
57 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
59 Status
= ExtractRequestedNvMap (FileFormTags
, VariableId
, &VariableDefinition
);
61 if (!EFI_ERROR (Status
)) {
63 // Allocate sufficient space for the data and copy it into the outgoing buffer
65 if (VariableSize
!= 0) {
66 *Buffer
= AllocateZeroPool (VariableSize
);
67 ASSERT (*Buffer
!= NULL
);
68 CopyMem (*Buffer
, &VariableDefinition
->NvRamMap
[OffsetValue
], VariableSize
);
79 IN EFI_FILE_FORM_TAGS
*FileFormTags
,
80 IN UI_MENU_OPTION
*MenuOption
87 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
91 SizeRequired
= MenuOption
->ThisTag
->StorageStart
+ MenuOption
->ThisTag
->StorageWidth
;
93 ExtractRequestedNvMap (FileFormTags
, MenuOption
->Tags
->VariableNumber
, &VariableDefinition
);
96 // We arrived here because the current NvRamMap is too small for the new op-code to store things and
97 // we need to adjust the buffer to support this.
99 NvRamMap
= AllocateZeroPool (SizeRequired
+ 1);
100 ASSERT (NvRamMap
!= NULL
);
103 // Copy current NvRamMap to the new NvRamMap
105 CopyMem (NvRamMap
, VariableDefinition
->NvRamMap
, VariableDefinition
->VariableFakeSize
);
108 // Remember, the only time we come here is because we are in the NVPlus section of the NvRamMap
110 for (Index
= MenuOption
->TagIndex
;
111 (MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_FORM_OP
) && (MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
);
115 switch (MenuOption
->Tags
[Index
].Operand
) {
116 case EFI_IFR_ORDERED_LIST_OP
:
117 case EFI_IFR_ONE_OF_OP
:
118 CachedStart
= MenuOption
->Tags
[Index
].StorageStart
;
121 case EFI_IFR_ONE_OF_OPTION_OP
:
122 if (MenuOption
->Tags
[Index
].Flags
& EFI_IFR_FLAG_DEFAULT
) {
123 CopyMem (&NvRamMap
[CachedStart
], &MenuOption
->Tags
[Index
].Value
, 2);
127 case EFI_IFR_CHECKBOX_OP
:
128 CopyMem (&NvRamMap
[MenuOption
->Tags
[Index
].StorageStart
], &MenuOption
->Tags
[Index
].Flags
, 1);
131 case EFI_IFR_NUMERIC_OP
:
132 case EFI_IFR_DATE_OP
:
133 case EFI_IFR_TIME_OP
:
134 case EFI_IFR_STRING_OP
:
135 case EFI_IFR_PASSWORD_OP
:
137 &NvRamMap
[MenuOption
->Tags
[Index
].StorageStart
],
138 &MenuOption
->Tags
[Index
].Value
,
139 MenuOption
->Tags
[Index
].StorageWidth
146 FreePool (VariableDefinition
->NvRamMap
);
147 VariableDefinition
->NvRamMap
= NvRamMap
;
148 VariableDefinition
->VariableFakeSize
= (UINT16
) SizeRequired
;
153 IN UI_MENU_OPTION
*MenuOption
,
155 IN EFI_FILE_FORM_TAGS
*FileFormTagsHead
,
156 IN EFI_IFR_DATA_ARRAY
*PageData
,
157 OUT CHAR16
**OptionString
164 EFI_FILE_FORM_TAGS
*FileFormTags
;
166 CHAR16 FormattedNumber
[6];
177 EFI_FORM_CALLBACK_PROTOCOL
*FormCallback
;
179 CHAR16 NullCharacter
;
181 EFI_VARIABLE_DEFINITION
*VariableDefinition
;
187 FileFormTags
= FileFormTagsHead
;
189 for (Index
= 0; Index
< MenuOption
->IfrNumber
; Index
++) {
190 FileFormTags
= FileFormTags
->NextFile
;
196 VariableDefinition
= NULL
;
199 ZeroMem (&Time
, sizeof (EFI_TIME
));
201 StringPtr
= (CHAR16
*) L
"\0";
202 Tag
= MenuOption
->ThisTag
;
203 ExtractRequestedNvMap (FileFormTags
, Tag
->VariableNumber
, &VariableDefinition
);
205 if (Tag
->StorageStart
> VariableDefinition
->VariableSize
) {
206 NvRamMap
= (UINT16
*) &VariableDefinition
->FakeNvRamMap
[Tag
->StorageStart
];
208 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
215 NullCharacter
= CHAR_NULL
;
218 if (MenuOption
->ThisTag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
220 if (((UINT8
*) NvRamMap
)[0] != 0x00) {
225 ZeroMem (FormattedNumber
, 12);
227 Status
= gBS
->HandleProtocol (
228 (VOID
*) (UINTN
) FileFormTags
->FormTags
.Tags
[0].CallbackHandle
,
229 &gEfiFormCallbackProtocolGuid
,
230 (VOID
**) &FormCallback
233 if (*OptionString
!= NULL
) {
234 FreePool (*OptionString
);
235 *OptionString
= NULL
;
238 switch (Tag
->Operand
) {
240 case EFI_IFR_ORDERED_LIST_OP
:
241 case EFI_IFR_ONE_OF_OP
:
243 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
244 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
245 // the NvMap so that we can properly display the information
247 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
248 AdjustNvMap (FileFormTags
, MenuOption
);
249 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
252 CachedIndex
= MenuOption
->TagIndex
;
255 // search for EFI_IFR_ONE_OF_OPTION_OP until you hit the EFI_IFR_END_ONE_OF_OP,
256 // each of the .Text in the options are going to be what gets displayed. Break each into 26 char chunks
257 // when hit right/left arrow allows for selection - then repopulate Tag[TagIndex] with the choice
259 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
; Index
++) {
261 // We found an option - which assumedly has a string. We will eventually have to support
262 // wrapping of strings. For now, let's pretend they don't wrap and code that up.
264 // Count how many strings there are
266 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
268 // If one of the options for the one-of has an interactive flag, back-define the oneof to have one too
270 if (MenuOption
->Tags
[Index
].Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
271 MenuOption
->Tags
[CachedIndex
].Flags
= (UINT8
) (MenuOption
->Tags
[CachedIndex
].Flags
| EFI_IFR_FLAG_INTERACTIVE
);
278 // We now know how many strings we will have, so we can allocate the
279 // space required for the array or strings.
281 *OptionString
= AllocateZeroPool (StringCount
* (gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
282 ASSERT (*OptionString
);
285 // Add left delimeter to string
287 *OptionString
[0] = LEFT_ONEOF_DELIMITER
;
290 // Retrieve the current OneOf value
294 // Auto selection from list
298 // Copy current setting to the seed Value
300 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
301 ValueArray
= AllocateZeroPool (MenuOption
->ThisTag
->StorageWidth
);
302 ASSERT (ValueArray
!= NULL
);
303 CopyMem (ValueArray
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
305 CopyMem (&Value
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
306 CopyMem (gPreviousValue
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
310 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
311 Status
= GetSelectionInputPopUp (MenuOption
, Tag
, MenuOption
->ThisTag
->StorageWidth
, ValueArray
, &KeyValue
);
313 Status
= GetSelectionInputPopUp (MenuOption
, Tag
, 1, &Value
, &KeyValue
);
316 if (!EFI_ERROR (Status
)) {
317 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
318 CopyMem (NvRamMap
, ValueArray
, MenuOption
->ThisTag
->StorageWidth
);
319 FreePool (ValueArray
);
322 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
324 CopyMem (NvRamMap
, &Value
, Tag
->StorageWidth
);
325 MenuOption
->ThisTag
->Key
= KeyValue
;
328 // If a late check is required save off the information. This is used when consistency checks
329 // are required, but certain values might be bound by an impossible consistency check such as
330 // if two questions are bound by consistency checks and each only has two possible choices, there
331 // would be no way for a user to switch the values. Thus we require late checking.
333 if (Tag
->Flags
& EFI_IFR_FLAG_LATE_CHECK
) {
334 CopyMem (&Tag
->OldValue
, &Value
, Tag
->StorageWidth
);
337 // In theory, passing the value and the Id are sufficient to determine what needs
338 // to be done. The Id is the key to look for the entry needed in the Inconsistency
339 // database. That will yields operand and ID data - and since the ID's correspond
340 // to the NV storage, we can determine the values for other IDs there.
342 if (ValueIsNotValid (TRUE
, 0, Tag
, FileFormTags
, &PopUp
)) {
343 if (PopUp
== 0x0000) {
347 if (!Tag
->Suppress
&& !Tag
->GrayOut
) {
348 CopyMem (NvRamMap
, &Number
, MenuOption
->ThisTag
->StorageWidth
);
353 StringPtr
= GetToken (PopUp
, MenuOption
->Handle
);
355 CreatePopUp (GetStringWidth (StringPtr
) / 2, 3, &NullCharacter
, StringPtr
, &NullCharacter
);
358 Status
= WaitForKeyStroke (&Key
);
360 switch (Key
.UnicodeChar
) {
362 case CHAR_CARRIAGE_RETURN
:
364 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
366 CopyMem (NvRamMap
, &Number
, MenuOption
->ThisTag
->StorageWidth
);
367 FreePool (StringPtr
);
373 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
377 UpdateStatusBar (NV_UPDATE_REQUIRED
, Tag
->Flags
, TRUE
);
379 if (Tag
->Operand
== EFI_IFR_ORDERED_LIST_OP
) {
380 FreePool (ValueArray
);
386 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
!= EFI_IFR_END_ONE_OF_OP
; Index
++) {
388 // We found an option - which assumedly has a string. We will eventually have to support
389 // wrapping of strings. For now, let's pretend they don't wrap and code that up.
391 if (MenuOption
->Tags
[Index
].Operand
== EFI_IFR_ONE_OF_OPTION_OP
) {
395 // If the first entry is invalid, then the "default" settings are based on what is reflected
396 // in the order of the op-codes
398 ((UINT8
*) NvRamMap
)[Index
- MenuOption
->TagIndex
- 1] = (UINT8
) MenuOption
->Tags
[Index
].Value
;
401 // Only display 3 lines of stuff at most
403 if ((Index
- MenuOption
->TagIndex
) > ORDERED_LIST_SIZE
) {
407 if (((Index
- MenuOption
->TagIndex
) != 1) && !Skip
) {
408 Character
[0] = LEFT_ONEOF_DELIMITER
;
409 NewStrCat (OptionString
[0], Character
);
412 MenuOption
->ThisTag
->NumberOfLines
= (UINT16
) (Index
- MenuOption
->TagIndex
);
414 StringPtr
= GetToken (MenuOption
->Tags
[Index
].Text
, MenuOption
->Handle
);
416 for (Value
= (UINT16
) (MenuOption
->TagIndex
+ 1);
417 MenuOption
->Tags
[Value
].Operand
!= EFI_IFR_END_ONE_OF_OP
;
420 if (MenuOption
->Tags
[Value
].Value
== ((UINT8
*) NvRamMap
)[Index
- MenuOption
->TagIndex
- 1]) {
421 StringPtr
= GetToken (MenuOption
->Tags
[Value
].Text
, MenuOption
->Handle
);
426 if (MenuOption
->Tags
[Value
].Operand
== EFI_IFR_END_ONE_OF_OP
) {
433 NewStrCat (OptionString
[0], StringPtr
);
434 Character
[0] = RIGHT_ONEOF_DELIMITER
;
435 NewStrCat (OptionString
[0], Character
);
436 Character
[0] = CHAR_CARRIAGE_RETURN
;
437 NewStrCat (OptionString
[0], Character
);
440 // Remove Buffer allocated for StringPtr after it has been used.
442 FreePool (StringPtr
);
445 // The option value is the same as what is stored in NV store. Print this.
447 if (!CompareMem (&(MenuOption
->Tags
[Index
].Value
), NvRamMap
, MenuOption
->ThisTag
->StorageWidth
)) {
448 StringPtr
= GetToken (MenuOption
->Tags
[Index
].Text
, MenuOption
->Handle
);
449 NewStrCat (OptionString
[0], StringPtr
);
450 Character
[0] = RIGHT_ONEOF_DELIMITER
;
451 NewStrCat (OptionString
[0], Character
);
453 // Remove Buffer allocated for StringPtr after it has been used.
455 FreePool (StringPtr
);
460 if ((MenuOption
->Tags
[Index
].Flags
& EFI_IFR_FLAG_DEFAULT
) == 1) {
461 Default
= MenuOption
->Tags
[Index
].Text
;
462 Value
= MenuOption
->Tags
[Index
].Value
;
468 // We didn't find a value that matched a setting in the NVRAM Map - display default - set default
472 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
474 CopyMem (NvRamMap
, &Value
, MenuOption
->ThisTag
->StorageWidth
);
476 StringPtr
= GetToken ((UINT16
) Default
, MenuOption
->Handle
);
477 NewStrCat (OptionString
[0], StringPtr
);
478 Character
[0] = RIGHT_ONEOF_DELIMITER
;
479 NewStrCat (OptionString
[0], Character
);
481 // Remove Buffer allocated for StringPtr after it has been used.
483 FreePool (StringPtr
);
488 case EFI_IFR_CHECKBOX_OP
:
490 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
491 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
492 // the NvMap so that we can properly display the information
494 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
495 AdjustNvMap (FileFormTags
, MenuOption
);
496 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
499 Default
= Tag
->Flags
& 1;
501 // If hit spacebar, set or unset Tag[TagIndex].Flags based on it's previous value - BOOLEAN
503 *OptionString
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
504 ASSERT (*OptionString
);
507 // Since Checkboxes are BOOLEAN values, bit 0 of the Flags bit defines the default option, therefore, if
508 // the default option (only one option for checkboxes) is on, then the default value is on. Tag.Default is not
509 // an active field for Checkboxes.
511 StrnCpy (OptionString
[0], (CHAR16
*) LEFT_CHECKBOX_DELIMITER
, 1);
514 // Since this is a BOOLEAN operation, flip bit 0 upon selection
517 Tag
->Value
= (UINT16
) (Tag
->Value
^ 1);
518 *(UINT8
*) NvRamMap
= (UINT8
) (Tag
->Value
& 1);
519 UpdateStatusBar (NV_UPDATE_REQUIRED
, Tag
->Flags
, TRUE
);
522 if ((*(UINT8
*) NvRamMap
& 1) == 0x01) {
523 NewStrCat (OptionString
[0], (CHAR16
*) CHECK_ON
);
525 // If someone reset default variables - we may need to reload from our NvMapping....
527 Tag
->Value
= *(UINT8
*) NvRamMap
;
530 // If someone reset default variables - we may need to reload from our NvMapping....
532 NewStrCat (OptionString
[0], (CHAR16
*) CHECK_OFF
);
533 Tag
->Value
= *(UINT8
*) NvRamMap
;
536 NewStrCat (OptionString
[0], (CHAR16
*) RIGHT_CHECKBOX_DELIMITER
);
537 NewStrCat (OptionString
[0], StringPtr
);
540 case EFI_IFR_NUMERIC_OP
:
542 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
543 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
544 // the NvMap so that we can properly display the information
546 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
547 AdjustNvMap (FileFormTags
, MenuOption
);
548 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
551 *OptionString
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
552 ASSERT (*OptionString
);
555 // Add left delimeter to string
557 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
560 // Retrieve the current numeric value
566 if (Tag
->Step
== 0) {
570 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, TRUE
, Tag
, REGULAR_NUMERIC
, &Number
);
571 if (!EFI_ERROR (Status
)) {
572 CopyMem (gPreviousValue
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
573 UpdateStatusBar (NV_UPDATE_REQUIRED
, Tag
->Flags
, TRUE
);
576 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
578 CopyMem (NvRamMap
, &Number
, MenuOption
->ThisTag
->StorageWidth
);
584 // Auto selection from list
586 if ((((Tag
->StorageWidth
== 1) && (UINT8
) (*NvRamMap
) > Tag
->Maximum
) || ((UINT8
) (*NvRamMap
) < Tag
->Minimum
)) ||
587 (((Tag
->StorageWidth
== 2) && *NvRamMap
> Tag
->Maximum
) || (*NvRamMap
< Tag
->Minimum
))
590 // Seed Number with valid value if currently invalid
592 Number
= Tag
->Default
;
594 if (Tag
->StorageWidth
== 1) {
595 Number
= (UINT8
) (*NvRamMap
);
601 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, FALSE
, Tag
, REGULAR_NUMERIC
, &Number
);
602 if (!EFI_ERROR (Status
)) {
603 CopyMem (gPreviousValue
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
604 UpdateStatusBar (NV_UPDATE_REQUIRED
, Tag
->Flags
, TRUE
);
607 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
609 CopyMem (NvRamMap
, &Number
, MenuOption
->ThisTag
->StorageWidth
);
615 if (((Tag
->StorageWidth
== 1) && (UINT8
) (*NvRamMap
) <= Tag
->Maximum
&& (UINT8
) (*NvRamMap
) >= Tag
->Minimum
) ||
616 ((Tag
->StorageWidth
== 2) && *NvRamMap
<= Tag
->Maximum
&& *NvRamMap
>= Tag
->Minimum
)
618 if (Tag
->StorageWidth
== 1) {
619 Number
= (UINT8
) (*NvRamMap
);
623 UnicodeValueToString (
627 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
629 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
630 StrnCpy (OptionString
[0] + 1, FormattedNumber
, Number
);
633 // If *NvRamMap isn't within parameters, set it to within parameters
636 // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth
638 CopyMem (NvRamMap
, &Tag
->Default
, MenuOption
->ThisTag
->StorageWidth
);
639 Number
= Tag
->Default
;
641 UnicodeValueToString (
645 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
647 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
648 StrnCpy (OptionString
[0] + 1, FormattedNumber
, Number
);
651 *(OptionString
[0] + Number
/ 2) = RIGHT_NUMERIC_DELIMITER
;
652 NewStrCat (OptionString
[0] + (Number
/ 2) + 1, StringPtr
);
656 case EFI_IFR_DATE_OP
:
658 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
659 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
660 // the NvMap so that we can properly display the information
662 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
663 AdjustNvMap (FileFormTags
, MenuOption
);
664 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
667 Status
= gRT
->GetTime (&Time
, NULL
);
668 if (EFI_ERROR (Status
)) {
672 // This for loop advances Index till it points immediately after a date entry. We can then
673 // subtract MenuOption->TagIndex from Index and find out relative to the start of the Date
674 // structure which field we were in. For instance, if TagIndex was 52, and we advanced Index
675 // to 53 and found it to no longer point to a date operand, we were pointing to the last of 3
679 // This has BUGBUG potential....fix this - if someone wants to ask two DATE questions in a row.....code
680 // against such silliness.
682 // Also, we want to internationalize the order of the date information. We need to code for it as well.
684 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
== EFI_IFR_DATE_OP
; Index
++)
688 // Count 0 = We entered on the first Date operand
689 // Count 1 = We entered on the second Date operand
690 // Count 2 = We entered on the third Date operand
692 Count
= 3 - (Index
- MenuOption
->TagIndex
);
697 // This is similar to numerics, except for the following:
698 // We will under normal circumstances get 3 consecutive calls
699 // to process this opcodes data.
701 *OptionString
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
702 ASSERT (*OptionString
);
707 Number
= (UINT16
) Time
.Month
;
709 if (Tag
->Step
== 0) {
710 MenuOption
->OptCol
++;
711 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, TRUE
, Tag
, DATE_NUMERIC
, &Number
);
714 // Seed value with current setting
716 Tag
->Value
= (UINT16
) Time
.Month
;
717 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, FALSE
, Tag
, DATE_NUMERIC
, &Number
);
720 if (!EFI_ERROR (Status
)) {
721 Time
.Month
= (UINT8
) Number
;
722 gRT
->SetTime (&Time
);
726 VariableDefinition
->FakeNvRamMap
[Tag
->Id
] = Time
.Month
;
727 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
729 UnicodeValueToString (
733 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
735 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
738 FormattedNumber
[2] = FormattedNumber
[1];
739 FormattedNumber
[1] = FormattedNumber
[0];
740 FormattedNumber
[0] = L
'0';
744 StrnCpy (OptionString
[0] + 1, FormattedNumber
, Number
);
745 *(OptionString
[0] + Number
/ 2) = DATE_SEPARATOR
;
746 StrCat (OptionString
[0] + (Number
/ 2) + 1, StringPtr
);
751 Number
= (UINT16
) Time
.Day
;
753 if (Tag
->Step
== 0) {
754 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, TRUE
, Tag
, DATE_NUMERIC
, &Number
);
757 // Seed value with current setting
759 Tag
->Value
= (UINT16
) Time
.Day
;
760 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, FALSE
, Tag
, DATE_NUMERIC
, &Number
);
763 if (!EFI_ERROR (Status
)) {
764 Time
.Day
= (UINT8
) Number
;
765 gRT
->SetTime (&Time
);
769 VariableDefinition
->FakeNvRamMap
[Tag
->Id
] = Time
.Day
;
770 SetUnicodeMem (OptionString
[0], 4, L
' ');
772 UnicodeValueToString (
776 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
778 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
780 FormattedNumber
[2] = FormattedNumber
[1];
781 FormattedNumber
[1] = FormattedNumber
[0];
782 FormattedNumber
[0] = L
'0';
786 StrnCpy (OptionString
[0] + 4, FormattedNumber
, Number
);
787 *(OptionString
[0] + Number
/ 2 + 3) = DATE_SEPARATOR
;
788 StrCat (OptionString
[0] + (Number
/ 2) + 4, StringPtr
);
793 Number
= (UINT16
) Time
.Year
;
795 if (Tag
->Step
== 0) {
796 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, TRUE
, Tag
, DATE_NUMERIC
, &Number
);
799 // Seed value with current setting
801 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, FALSE
, Tag
, DATE_NUMERIC
, &Number
);
804 if (!EFI_ERROR (Status
)) {
805 Time
.Year
= (UINT16
) Number
;
806 gRT
->SetTime (&Time
);
810 Tag
->Value
= (UINT16
) Time
.Year
;
811 VariableDefinition
->FakeNvRamMap
[Tag
->Id
] = (UINT8
) Tag
->Value
;
812 VariableDefinition
->FakeNvRamMap
[Tag
->Id
+ 1] = (UINT8
) (Tag
->Value
>> 8);
813 SetUnicodeMem (OptionString
[0], 7, L
' ');
814 UnicodeValueToString (
818 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
820 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
821 StrnCpy (OptionString
[0] + 7, FormattedNumber
, Number
);
822 *(OptionString
[0] + Number
/ 2 + 6) = RIGHT_NUMERIC_DELIMITER
;
823 StrCat (OptionString
[0] + (Number
/ 2) + 7, StringPtr
);
830 // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
831 // We need to add code to support the NVRam storage version of Date - this is the 1% case where someone
832 // might want to set an alarm and actually preserve the data in NVRam so a driver can pick up the instruction
833 // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
835 case EFI_IFR_TIME_OP
:
837 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
838 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
839 // the NvMap so that we can properly display the information
841 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
842 AdjustNvMap (FileFormTags
, MenuOption
);
843 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
846 Status
= gRT
->GetTime (&Time
, NULL
);
847 if (EFI_ERROR (Status
)) {
851 // This is similar to numerics, except for the following:
852 // We will under normal circumstances get 3 consecutive calls
853 // to process this opcodes data.
855 *OptionString
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
856 ASSERT (*OptionString
);
859 // This for loop advances Index till it points immediately after a date entry. We can then
860 // subtract MenuOption->TagIndex from Index and find out relative to the start of the Date
861 // structure which field we were in. For instance, if TagIndex was 52, and we advanced Index
862 // to 53 and found it to no longer point to a date operand, we were pointing to the last of 3
865 for (Index
= MenuOption
->TagIndex
; MenuOption
->Tags
[Index
].Operand
== EFI_IFR_TIME_OP
; Index
++)
868 // Count 0 = We entered on the first Date operand
869 // Count 1 = We entered on the second Date operand
870 // Count 2 = We entered on the third Date operand
872 Count
= 3 - (Index
- MenuOption
->TagIndex
);
883 Number
= Time
.Minute
;
887 Number
= Time
.Second
;
890 // Retrieve the current numeric value
896 if (Tag
->Step
== 0) {
900 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, TRUE
, Tag
, TIME_NUMERIC
, &Number
);
901 if (!EFI_ERROR (Status
)) {
904 gRT
->SetTime (&Time
);
910 // Auto selection from list
912 Status
= GetNumericInput (MenuOption
, FileFormTagsHead
, FALSE
, Tag
, TIME_NUMERIC
, &Number
);
913 if (!EFI_ERROR (Status
)) {
922 Time
.Hour
= (UINT8
) Number
;
926 Time
.Minute
= (UINT8
) Number
;
930 Time
.Second
= (UINT8
) Number
;
934 gRT
->SetTime (&Time
);
938 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
939 UnicodeValueToString (
943 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
945 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
947 FormattedNumber
[2] = FormattedNumber
[1];
948 FormattedNumber
[1] = FormattedNumber
[0];
949 FormattedNumber
[0] = L
'0';
953 StrnCpy (OptionString
[0] + 1, FormattedNumber
, Number
);
954 *(OptionString
[0] + Number
/ 2) = TIME_SEPARATOR
;
955 StrCat (OptionString
[0] + (Number
/ 2) + 1, StringPtr
);
959 SetUnicodeMem (OptionString
[0], 4, L
' ');
960 UnicodeValueToString (
964 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
966 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
968 FormattedNumber
[2] = FormattedNumber
[1];
969 FormattedNumber
[1] = FormattedNumber
[0];
970 FormattedNumber
[0] = L
'0';
974 StrnCpy (OptionString
[0] + 4, FormattedNumber
, Number
);
975 *(OptionString
[0] + Number
/ 2 + 3) = TIME_SEPARATOR
;
976 StrCat (OptionString
[0] + (Number
/ 2) + 4, StringPtr
);
980 SetUnicodeMem (OptionString
[0], 7, L
' ');
981 UnicodeValueToString (
985 (sizeof (FormattedNumber
) / sizeof (FormattedNumber
[0]))
987 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
989 FormattedNumber
[2] = FormattedNumber
[1];
990 FormattedNumber
[1] = FormattedNumber
[0];
991 FormattedNumber
[0] = L
'0';
995 StrnCpy (OptionString
[0] + 7, FormattedNumber
, Number
);
996 *(OptionString
[0] + Number
/ 2 + 6) = RIGHT_NUMERIC_DELIMITER
;
997 StrCat (OptionString
[0] + (Number
/ 2) + 7, StringPtr
);
1001 // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
1002 // We need to add code to support the NVRam storage version of Date - this is the 1% case where someone
1003 // might want to set an alarm and actually preserve the data in NVRam so a driver can pick up the instruction
1004 // BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG BUGBUG
1009 case EFI_IFR_STRING_OP
:
1011 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
1012 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
1013 // the NvMap so that we can properly display the information
1015 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
1016 AdjustNvMap (FileFormTags
, MenuOption
);
1017 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
1020 *OptionString
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
);
1021 ASSERT (*OptionString
);
1024 StringPtr
= AllocateZeroPool (Tag
->Maximum
);
1027 Status
= ReadString (MenuOption
, StringPtr
);
1029 if (!EFI_ERROR (Status
)) {
1030 CopyMem (gPreviousValue
, NvRamMap
, MenuOption
->ThisTag
->StorageWidth
);
1031 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], StringPtr
, Tag
->StorageWidth
);
1033 UpdateStatusBar (NV_UPDATE_REQUIRED
, Tag
->Flags
, TRUE
);
1036 FreePool (StringPtr
);
1039 for (Index
= 0; Index
< gOptionBlockWidth
; Index
++) {
1040 if (VariableDefinition
->NvRamMap
[Tag
->StorageStart
+ (Index
* 2)] != 0x0000) {
1041 CopyMem (OptionString
[0] + Index
, &VariableDefinition
->NvRamMap
[Tag
->StorageStart
+ (Index
* 2)], 2);
1044 *(OptionString
[0] + Index
) = '_';
1045 *(OptionString
[0] + 1 + Index
) = 0;
1054 case EFI_IFR_PASSWORD_OP
:
1056 // If the op-code we are looking at is larger than the latest created NvMap - we likely encountered a dynamically
1057 // created entry which has an expanded NvMap requirement. We won't save this information - but we need to adjust
1058 // the NvMap so that we can properly display the information
1060 if ((UINTN
) (Tag
->StorageStart
+ Tag
->StorageWidth
) > VariableDefinition
->VariableFakeSize
) {
1061 AdjustNvMap (FileFormTags
, MenuOption
);
1062 NvRamMap
= (UINT16
*) &VariableDefinition
->NvRamMap
[Tag
->StorageStart
];
1066 StringPtr
= AllocateZeroPool (Tag
->Maximum
);
1070 // If interactive, read the password and do the appropriate callbacks in that routine.
1071 // Since interactive passwords assume to handle the password data in a separate variable
1072 // storage, we don't need to do more than what is below for password callbacks
1074 if (Tag
->Flags
& EFI_IFR_FLAG_INTERACTIVE
) {
1075 MenuOption
->Tags
[0].CallbackHandle
= FileFormTags
->FormTags
.Tags
[0].CallbackHandle
;
1076 Status
= ReadPassword (MenuOption
, TRUE
, Tag
, PageData
, FALSE
, FileFormTags
, StringPtr
);
1077 ZeroMem (StringPtr
, Tag
->Maximum
);
1079 if (EFI_ERROR (Status
)) {
1080 if (Status
== EFI_NOT_READY
) {
1081 FreePool (StringPtr
);
1086 Status
= ReadPassword (MenuOption
, TRUE
, Tag
, PageData
, TRUE
, FileFormTags
, StringPtr
);
1087 FreePool (StringPtr
);
1091 for (Index
= 0; Index
< Tag
->Maximum
; Index
++) {
1092 if (VariableDefinition
->NvRamMap
[Tag
->StorageStart
+ Index
] != 0x00) {
1094 // There is something there! Prompt for password
1096 Status
= ReadPassword (MenuOption
, TRUE
, Tag
, PageData
, FALSE
, FileFormTags
, StringPtr
);
1097 if (EFI_ERROR (Status
)) {
1098 FreePool (StringPtr
);
1102 if (Tag
->Encoding
== 1) {
1103 EncodePassword (StringPtr
, (UINT8
) Tag
->Maximum
);
1104 Status
= CompareMem (StringPtr
, &VariableDefinition
->NvRamMap
[Tag
->StorageStart
], Tag
->Maximum
);
1106 Status
= CompareMem (StringPtr
, &VariableDefinition
->NvRamMap
[Tag
->StorageStart
], Tag
->Maximum
);
1110 FreePool (StringPtr
);
1120 ZeroMem (StringPtr
, Tag
->Maximum
);
1123 // No password set! Go ahead and prompt the user for a password.
1125 Status
= ReadPassword (MenuOption
, FALSE
, Tag
, PageData
, FALSE
, FileFormTags
, StringPtr
);
1127 if (EFI_ERROR (Status
)) {
1129 // User couldn't figure out how to type two identical passwords
1131 FreePool (StringPtr
);
1135 // Very simple example of how one MIGHT do password encoding
1137 if (Tag
->Encoding
== 1) {
1138 EncodePassword (StringPtr
, (UINT8
) Tag
->Maximum
);
1141 TmpNvRamMap
= AllocatePool (VariableDefinition
->VariableSize
);
1142 ASSERT (TmpNvRamMap
!= NULL
);
1144 Count
= VariableDefinition
->VariableSize
;
1146 if ((FormCallback
!= NULL
) && (FormCallback
->NvRead
!= NULL
)) {
1147 Status
= FormCallback
->NvRead (
1149 VariableDefinition
->VariableName
,
1150 &VariableDefinition
->Guid
,
1153 (VOID
*) TmpNvRamMap
1156 Status
= gRT
->GetVariable (
1157 VariableDefinition
->VariableName
,
1158 &VariableDefinition
->Guid
,
1161 (VOID
*) TmpNvRamMap
1165 CopyMem (&VariableDefinition
->NvRamMap
[Tag
->StorageStart
], StringPtr
, Tag
->StorageWidth
);
1166 CopyMem (&TmpNvRamMap
[Tag
->StorageStart
], StringPtr
, Tag
->StorageWidth
);
1168 if ((FormCallback
!= NULL
) && (FormCallback
->NvWrite
!= NULL
)) {
1169 Status
= FormCallback
->NvWrite (
1171 VariableDefinition
->VariableName
,
1172 &VariableDefinition
->Guid
,
1173 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1174 VariableDefinition
->VariableSize
,
1175 (VOID
*) TmpNvRamMap
,
1179 Status
= gRT
->SetVariable (
1180 VariableDefinition
->VariableName
,
1181 &VariableDefinition
->Guid
,
1182 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
1183 VariableDefinition
->VariableSize
,
1184 (VOID
*) TmpNvRamMap
1188 FreePool (TmpNvRamMap
);
1189 FreePool (StringPtr
);
1201 Split StringPtr to several lines of strings stored in FormattedString and the glyph width of
1202 each line cannot exceed gHelpBlockWidth.
1204 @param StringPtr The pointer of string
1205 @param FormattedString The pointer of format string
1206 @param RowCount The count of row
1211 IN CHAR16
*StringPtr
,
1212 OUT CHAR16
**FormattedString
,
1216 CONST UINTN BlockWidth
= (UINTN
) gHelpBlockWidth
- 1;
1219 // [PrevCurrIndex, CurrIndex) forms a range of a screen-line
1222 UINTN PrevCurrIndex
;
1224 UINTN VirtualLineCount
;
1226 // GlyphOffset stores glyph width of current screen-line
1230 // GlyphWidth equals to 2 if we meet width directive
1234 // during scanning, we remember the position of last space character
1235 // in case that if next word cannot put in current line, we could restore back to the position
1236 // of last space character
1237 // while we should also remmeber the glyph width of the last space character for restoring
1239 UINTN LastSpaceIndex
;
1240 UINTN LastSpaceGlyphWidth
;
1242 // every time we begin to form a new screen-line, we should remember glyph width of single character
1245 UINTN LineStartGlyphWidth
;
1247 UINTN
*OldIndexArray
;
1250 // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )
1251 // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want
1252 // to bring the width directive of the last line to current screen-line.
1253 // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line
1254 // different from that of "\wideabcde", we should remember the width directive.
1256 AllocateSize
= 0x20;
1257 IndexArray
= AllocatePool (AllocateSize
* sizeof (UINTN
) * 3);
1259 if (*FormattedString
!= NULL
) {
1260 FreePool (*FormattedString
);
1261 *FormattedString
= NULL
;
1264 for (PrevCurrIndex
= 0, CurrIndex
= 0, LineCount
= 0, LastSpaceIndex
= 0,
1265 IndexArray
[0] = 0, GlyphWidth
= 1, GlyphOffset
= 0, LastSpaceGlyphWidth
= 1, LineStartGlyphWidth
= 1;
1266 (StringPtr
[CurrIndex
] != CHAR_NULL
);
1269 if (LineCount
== AllocateSize
) {
1270 AllocateSize
+= 0x10;
1271 OldIndexArray
= IndexArray
;
1272 IndexArray
= AllocatePool (AllocateSize
* sizeof (UINTN
) * 3);
1273 CopyMem (IndexArray
, OldIndexArray
, LineCount
* sizeof (UINTN
) * 3);
1274 if (OldIndexArray
!= NULL
) {
1275 FreePool (OldIndexArray
);
1279 switch (StringPtr
[CurrIndex
]) {
1283 GlyphWidth
= ((StringPtr
[CurrIndex
] == WIDE_CHAR
) ? 2 : 1);
1284 if (CurrIndex
== 0) {
1285 LineStartGlyphWidth
= GlyphWidth
;
1291 // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN
1295 // Store a range of string as a line
1297 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1298 IndexArray
[LineCount
*3+1] = CurrIndex
;
1299 IndexArray
[LineCount
*3+2] = LineStartGlyphWidth
;
1302 // Reset offset and save begin position of line
1305 LineStartGlyphWidth
= GlyphWidth
;
1306 PrevCurrIndex
= CurrIndex
+ 1;
1311 // "\r\n" and "\r" both are handled here
1313 case CHAR_CARRIAGE_RETURN
:
1314 if (StringPtr
[CurrIndex
+ 1] == CHAR_LINEFEED
) {
1316 // next char is '\n'
1318 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1319 IndexArray
[LineCount
*3+1] = CurrIndex
;
1320 IndexArray
[LineCount
*3+2] = LineStartGlyphWidth
;
1325 LineStartGlyphWidth
= GlyphWidth
;
1326 PrevCurrIndex
= CurrIndex
+ 1;
1330 // char is space or other char
1333 GlyphOffset
+= GlyphWidth
;
1334 if (GlyphOffset
>= BlockWidth
) {
1335 if (LastSpaceIndex
> PrevCurrIndex
) {
1337 // LastSpaceIndex points to space inside current screen-line,
1338 // restore to LastSpaceIndex
1339 // (Otherwise the word is too long to fit one screen-line, just cut it)
1341 CurrIndex
= LastSpaceIndex
;
1342 GlyphWidth
= LastSpaceGlyphWidth
;
1343 } else if (GlyphOffset
> BlockWidth
) {
1345 // the word is too long to fit one screen-line and we don't get the chance
1346 // of GlyphOffset == BlockWidth because GlyphWidth = 2
1351 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1352 IndexArray
[LineCount
*3+1] = CurrIndex
+ 1;
1353 IndexArray
[LineCount
*3+2] = LineStartGlyphWidth
;
1354 LineStartGlyphWidth
= GlyphWidth
;
1357 // Reset offset and save begin position of line
1360 PrevCurrIndex
= CurrIndex
+ 1;
1364 // LastSpaceIndex: remember position of last space
1366 if (StringPtr
[CurrIndex
] == CHAR_SPACE
) {
1367 LastSpaceIndex
= CurrIndex
;
1368 LastSpaceGlyphWidth
= GlyphWidth
;
1374 if (GlyphOffset
> 0) {
1375 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1376 IndexArray
[LineCount
*3+1] = CurrIndex
;
1377 IndexArray
[LineCount
*3+2] = GlyphWidth
;
1381 if (LineCount
== 0) {
1383 // in case we meet null string
1388 // we assume null string's glyph width is 1
1394 VirtualLineCount
= RowCount
* (LineCount
/ RowCount
+ (LineCount
% RowCount
> 0));
1395 *FormattedString
= AllocateZeroPool (VirtualLineCount
* (BlockWidth
+ 1) * sizeof (CHAR16
) * 2);
1397 for (CurrIndex
= 0; CurrIndex
< LineCount
; CurrIndex
++) {
1398 *(*FormattedString
+ CurrIndex
* 2 * (BlockWidth
+ 1)) = (CHAR16
)((IndexArray
[CurrIndex
*3+2] == 2) ? WIDE_CHAR
: NARROW_CHAR
);
1400 *FormattedString
+ CurrIndex
* 2 * (BlockWidth
+ 1) + 1,
1401 StringPtr
+ IndexArray
[CurrIndex
*3],
1402 IndexArray
[CurrIndex
*3+1]-IndexArray
[CurrIndex
*3]
1406 if (IndexArray
!= NULL
) {
1407 FreePool (IndexArray
);
1414 IN EFI_TAG
*TargetTag
,
1416 EFI_VARIABLE_DEFINITION
*VariableDefinitionsHead
1420 CHAR16
*VariableName
;
1422 EFI_VARIABLE_DEFINITION
*VariableDefinitions
;
1423 EFI_VARIABLE_DEFINITION
*PreviousVariableDefinitions
;
1424 STATIC UINT16 VariableSize
;
1426 STATIC UINT16 CurrentVariable
;
1427 STATIC UINT16 CurrentVariable2
;
1431 case EFI_IFR_FORM_OP
:
1432 CopyMem (&TargetTag
->Id
, &((EFI_IFR_FORM
*) FormData
)->FormId
, sizeof (UINT16
));
1433 CopyMem (&TargetTag
->Text
, &((EFI_IFR_FORM
*) FormData
)->FormTitle
, sizeof (UINT16
));
1434 TargetTag
->VariableNumber
= CurrentVariable
;
1435 if (VariableDefinitionsHead
!= NULL
) {
1436 VariableName
= AllocateZeroPool (12);
1437 ASSERT (VariableName
!= NULL
);
1438 CopyMem (VariableName
, L
"Setup", 12);
1439 VariableDefinitionsHead
->VariableName
= VariableName
;
1440 VariableDefinitionsHead
->VariableSize
= VariableSize
;
1441 CopyMem (&VariableDefinitionsHead
->Guid
, &Guid
, sizeof (EFI_GUID
));
1445 case EFI_IFR_SUBTITLE_OP
:
1446 TargetTag
->NumberOfLines
= 1;
1447 CopyMem (&TargetTag
->Text
, &((EFI_IFR_SUBTITLE
*) FormData
)->SubTitle
, sizeof (UINT16
));
1448 TargetTag
->VariableNumber
= CurrentVariable
;
1451 case EFI_IFR_TEXT_OP
:
1452 TargetTag
->NumberOfLines
= 1;
1453 CopyMem (&TargetTag
->Text
, &((EFI_IFR_TEXT
*) FormData
)->Text
, sizeof (UINT16
));
1454 CopyMem (&TargetTag
->Help
, &((EFI_IFR_TEXT
*) FormData
)->Help
, sizeof (UINT16
));
1455 TargetTag
->VariableNumber
= CurrentVariable
;
1458 // To optimize the encoding size, certain opcodes have optional fields such as those
1459 // inside the if() statement. If the encoded length is the complete size, then we
1460 // know we have valid data encoded that we want to integrate
1462 if (((EFI_IFR_TEXT
*) FormData
)->Header
.Length
== sizeof (EFI_IFR_TEXT
)) {
1464 // Text has no help associated with it, but in case there is a second entry due to
1465 // dynamic/interactive flags being active, bring this data over.
1467 CopyMem (&TargetTag
->TextTwo
, &((EFI_IFR_TEXT
*) FormData
)->TextTwo
, sizeof (UINT16
));
1468 TargetTag
->Flags
= ((EFI_IFR_TEXT
*) FormData
)->Flags
;
1469 CopyMem (&TargetTag
->Key
, &((EFI_IFR_TEXT
*) FormData
)->Key
, sizeof (UINT16
));
1473 case EFI_IFR_ONE_OF_OPTION_OP
:
1474 CopyMem (&TargetTag
->Text
, &((EFI_IFR_ONE_OF_OPTION
*) FormData
)->Option
, sizeof (UINT16
));
1475 CopyMem (&TargetTag
->Value
, &((EFI_IFR_ONE_OF_OPTION
*) FormData
)->Value
, sizeof (UINT16
));
1476 TargetTag
->Flags
= ((EFI_IFR_ONE_OF_OPTION
*) FormData
)->Flags
;
1477 CopyMem (&TargetTag
->Key
, &((EFI_IFR_ONE_OF_OPTION
*) FormData
)->Key
, sizeof (UINT16
));
1478 TargetTag
->VariableNumber
= CurrentVariable
;
1481 case EFI_IFR_CHECKBOX_OP
:
1482 TargetTag
->Flags
= ((EFI_IFR_CHECKBOX
*) FormData
)->Flags
;
1483 TargetTag
->ResetRequired
= (BOOLEAN
) (TargetTag
->Flags
& EFI_IFR_FLAG_RESET_REQUIRED
);
1484 CopyMem (&TargetTag
->Key
, &((EFI_IFR_CHECKBOX
*) FormData
)->Key
, sizeof (UINT16
));
1485 TargetTag
->VariableNumber
= CurrentVariable
;
1488 case EFI_IFR_NUMERIC_OP
:
1489 TargetTag
->Flags
= ((EFI_IFR_NUMERIC
*) FormData
)->Flags
;
1490 CopyMem (&TargetTag
->Key
, &((EFI_IFR_NUMERIC
*) FormData
)->Key
, sizeof (UINT16
));
1491 TargetTag
->VariableNumber
= CurrentVariable
;
1494 case EFI_IFR_STRING_OP
:
1496 // Convert EFI_IFR_STRING.MinSize and EFI_IFR_STRING.MaxSize to actual minimum and maximum bytes
1497 // and store to EFI_TAG.Minimum and EFI_TAG.Maximum
1500 CopyMem (&TempValue
, &((EFI_IFR_STRING
*) FormData
)->MinSize
, sizeof (UINT8
));
1501 TempValue
= (UINT16
) (TempValue
* 2);
1502 CopyMem (&TargetTag
->Minimum
, &TempValue
, sizeof (UINT16
));
1505 CopyMem (&TempValue
, &((EFI_IFR_STRING
*) FormData
)->MaxSize
, sizeof (UINT8
));
1506 TempValue
= (UINT16
) (TempValue
* 2);
1507 CopyMem (&TargetTag
->Maximum
, &TempValue
, sizeof (UINT16
));
1508 CopyMem (&TargetTag
->StorageWidth
, &TempValue
, sizeof (UINT16
));
1509 TargetTag
->Flags
= (UINT8
) (((EFI_IFR_STRING
*) FormData
)->Flags
);
1510 TargetTag
->ResetRequired
= (BOOLEAN
) (TargetTag
->Flags
& EFI_IFR_FLAG_RESET_REQUIRED
);
1511 CopyMem (&TargetTag
->Key
, &((EFI_IFR_STRING
*) FormData
)->Key
, sizeof (UINT16
));
1512 TargetTag
->VariableNumber
= CurrentVariable
;
1515 case EFI_IFR_PASSWORD_OP
:
1517 CopyMem (&TempValue
, &((EFI_IFR_PASSWORD
*) FormData
)->MinSize
, sizeof (UINT8
));
1518 TempValue
= (UINT16
) (TempValue
* 2);
1519 CopyMem (&TargetTag
->Minimum
, &TempValue
, sizeof (UINT16
));
1522 CopyMem (&TempValue
, &((EFI_IFR_PASSWORD
*) FormData
)->MaxSize
, sizeof (UINT8
));
1523 TempValue
= (UINT16
) (TempValue
* 2);
1524 CopyMem (&TargetTag
->Maximum
, &TempValue
, sizeof (UINT16
));
1525 CopyMem (&TargetTag
->StorageWidth
, &TempValue
, sizeof (UINT16
));
1526 TargetTag
->Flags
= ((EFI_IFR_PASSWORD
*) FormData
)->Flags
;
1527 TargetTag
->ResetRequired
= (BOOLEAN
) (TargetTag
->Flags
& EFI_IFR_FLAG_RESET_REQUIRED
);
1528 CopyMem (&TargetTag
->Key
, &((EFI_IFR_PASSWORD
*) FormData
)->Key
, sizeof (UINT16
));
1529 CopyMem (&TargetTag
->Encoding
, &((EFI_IFR_PASSWORD
*) FormData
)->Encoding
, sizeof (UINT16
));
1530 TargetTag
->VariableNumber
= CurrentVariable
;
1533 case EFI_IFR_VARSTORE_OP
:
1535 // It should NEVER be NULL
1537 if (VariableDefinitionsHead
== NULL
) {
1541 VariableDefinitions
= VariableDefinitionsHead
;
1544 // Advance VariableDefinitions to the last entry
1546 for (; VariableDefinitions
!= NULL
; VariableDefinitions
= VariableDefinitions
->Next
) {
1547 PreviousVariableDefinitions
= VariableDefinitions
;
1549 // If there is a variable with this GUID and ID already, we need to bail out
1551 if (!CompareMem (&VariableDefinitions
->Guid
, &((EFI_IFR_VARSTORE
*) FormData
)->Guid
, sizeof (EFI_GUID
)) &&
1552 !CompareMem (&VariableDefinitions
->VariableId
, &((EFI_IFR_VARSTORE
*) FormData
)->VarId
, sizeof (UINT16
))
1557 if (VariableDefinitions
->Next
== NULL
) {
1562 // If the last entry has a variable in it already, allocate a new entry and use it
1564 if (VariableDefinitions
->VariableName
!= NULL
) {
1565 VariableDefinitions
->Next
= AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION
));
1566 ASSERT (VariableDefinitions
->Next
!= NULL
);
1567 PreviousVariableDefinitions
= VariableDefinitions
;
1568 VariableDefinitions
= VariableDefinitions
->Next
;
1569 VariableDefinitions
->Previous
= PreviousVariableDefinitions
;
1572 // Copy the Variable data to our linked list
1574 CopyMem (&VariableDefinitions
->VariableId
, &((EFI_IFR_VARSTORE
*) FormData
)->VarId
, sizeof (UINT16
));
1575 CopyMem (&VariableDefinitions
->VariableSize
, &((EFI_IFR_VARSTORE
*) FormData
)->Size
, sizeof (UINT16
));
1576 CopyMem (&VariableDefinitions
->Guid
, &((EFI_IFR_VARSTORE
*) FormData
)->Guid
, sizeof (EFI_GUID
));
1579 // The ASCII String which is immediately past the EFI_IFR_VARSTORE is inferred by the structure definition
1580 // due to it being variable sized. There are rules preventing it from being > 40 characters long and should
1581 // be enforced by the compiler.
1583 AsciiString
= (CHAR8
*) (&((EFI_IFR_VARSTORE
*) FormData
)->Size
);
1584 AsciiString
= AsciiString
+ 2;
1585 VariableDefinitions
->VariableName
= AllocateZeroPool ((AsciiStrLen (AsciiString
) + 1) * 2);
1586 ASSERT (VariableDefinitions
->VariableName
!= NULL
);
1587 for (Index
= 0; AsciiString
[Index
] != 0; Index
++) {
1588 VariableDefinitions
->VariableName
[Index
] = (CHAR16
) AsciiString
[Index
];
1591 VariableDefinitions
->VariableName
[Index
] = 0;
1594 // Propogate the tag information for this op-code
1596 CopyMem (&TargetTag
->VariableNumber
, &((EFI_IFR_VARSTORE
*) FormData
)->VarId
, sizeof (UINT16
));
1597 CopyMem (&TargetTag
->GuidValue
, &((EFI_IFR_VARSTORE
*) FormData
)->Guid
, sizeof (EFI_GUID
));
1598 CopyMem (&TargetTag
->StorageWidth
, &((EFI_IFR_VARSTORE
*) FormData
)->Size
, sizeof (UINT16
));
1599 CopyMem (&TargetTag
->Maximum
, &((EFI_IFR_VARSTORE
*) FormData
)->Size
, sizeof (UINT16
));
1602 case EFI_IFR_VARSTORE_SELECT_OP
:
1603 CopyMem (&TargetTag
->VariableNumber
, &((EFI_IFR_VARSTORE_SELECT
*) FormData
)->VarId
, sizeof (UINT16
));
1604 CopyMem (&CurrentVariable
, &((EFI_IFR_VARSTORE_SELECT
*) FormData
)->VarId
, sizeof (UINT16
));
1605 CurrentVariable2
= CurrentVariable
;
1608 case EFI_IFR_VARSTORE_SELECT_PAIR_OP
:
1609 CopyMem (&TargetTag
->VariableNumber
, &((EFI_IFR_VARSTORE_SELECT_PAIR
*) FormData
)->VarId
, sizeof (UINT16
));
1611 &TargetTag
->VariableNumber2
,
1612 &((EFI_IFR_VARSTORE_SELECT_PAIR
*) FormData
)->SecondaryVarId
,
1615 CopyMem (&CurrentVariable
, &((EFI_IFR_VARSTORE_SELECT_PAIR
*) FormData
)->VarId
, sizeof (UINT16
));
1616 CopyMem (&CurrentVariable2
, &((EFI_IFR_VARSTORE_SELECT_PAIR
*) FormData
)->SecondaryVarId
, sizeof (UINT16
));
1619 case EFI_IFR_REF_OP
:
1620 TargetTag
->NumberOfLines
= 1;
1621 CopyMem (&TargetTag
->Id
, &((EFI_IFR_REF
*) FormData
)->FormId
, sizeof (UINT16
));
1622 CopyMem (&TargetTag
->Key
, &((EFI_IFR_REF
*) FormData
)->Key
, sizeof (UINT16
));
1623 CopyMem (&TargetTag
->Text
, &((EFI_IFR_REF
*) FormData
)->Prompt
, sizeof (UINT16
));
1624 CopyMem (&TargetTag
->Help
, &((EFI_IFR_REF
*) FormData
)->Help
, sizeof (UINT16
));
1625 TargetTag
->Flags
= ((EFI_IFR_REF
*) FormData
)->Flags
;
1626 TargetTag
->VariableNumber
= CurrentVariable
;
1629 case EFI_IFR_EQ_ID_VAL_OP
:
1630 CopyMem (&TargetTag
->Value
, &((EFI_IFR_EQ_ID_VAL
*) FormData
)->Value
, sizeof (UINT16
));
1631 CopyMem (&TargetTag
->Id
, &((EFI_IFR_EQ_ID_VAL
*) FormData
)->QuestionId
, sizeof (UINT16
));
1632 TargetTag
->StorageWidth
= ((EFI_IFR_EQ_ID_VAL
*) FormData
)->Width
;
1633 TargetTag
->VariableNumber
= CurrentVariable
;
1636 case EFI_IFR_EQ_VAR_VAL_OP
:
1637 CopyMem (&TargetTag
->Value
, &((EFI_IFR_EQ_VAR_VAL
*) FormData
)->Value
, sizeof (UINT16
));
1638 CopyMem (&TargetTag
->Id
, &((EFI_IFR_EQ_VAR_VAL
*) FormData
)->VariableId
, sizeof (UINT16
));
1639 TargetTag
->VariableNumber
= CurrentVariable
;
1642 case EFI_IFR_EQ_ID_ID_OP
:
1643 CopyMem (&TargetTag
->Id
, &((EFI_IFR_EQ_ID_ID
*) FormData
)->QuestionId1
, sizeof (UINT16
));
1644 CopyMem (&TargetTag
->Id2
, &((EFI_IFR_EQ_ID_ID
*) FormData
)->QuestionId2
, sizeof (UINT16
));
1645 TargetTag
->StorageWidth
= ((EFI_IFR_EQ_ID_ID
*) FormData
)->Width
;
1646 TargetTag
->VariableNumber
= CurrentVariable
;
1647 TargetTag
->VariableNumber
= CurrentVariable2
;
1650 case EFI_IFR_EQ_ID_LIST_OP
:
1651 CopyMem (&TargetTag
->Id
, &((EFI_IFR_EQ_ID_LIST
*) FormData
)->QuestionId
, sizeof (UINT16
));
1652 CopyMem (&TargetTag
->Id2
, &((EFI_IFR_EQ_ID_LIST
*) FormData
)->ListLength
, sizeof (UINT16
));
1653 TargetTag
->StorageWidth
= ((EFI_IFR_EQ_ID_LIST
*) FormData
)->Width
;
1655 TargetTag
->IntList
= AllocateZeroPool (TargetTag
->Id2
* sizeof (UINT16
));
1656 ASSERT (TargetTag
->IntList
);
1658 for (TempValue
= 0; TempValue
< TargetTag
->Id2
; TempValue
++) {
1660 &TargetTag
->IntList
[TempValue
],
1661 &((EFI_IFR_EQ_ID_LIST
*) FormData
)->ValueList
[TempValue
],
1666 TargetTag
->VariableNumber
= CurrentVariable
;
1669 case EFI_IFR_FORM_SET_OP
:
1670 CopyMem (&VariableSize
, &((EFI_IFR_FORM_SET
*) FormData
)->NvDataSize
, sizeof (UINT16
));
1671 CopyMem (&Guid
, &((EFI_IFR_FORM_SET
*) FormData
)->Guid
, sizeof (EFI_GUID
));
1673 // If there is a size specified in the formste, we will establish a "default" variable
1675 if (VariableDefinitionsHead
!= NULL
) {
1676 VariableName
= AllocateZeroPool (12);
1677 ASSERT (VariableName
!= NULL
);
1678 CopyMem (VariableName
, L
"Setup", 12);
1679 VariableDefinitionsHead
->VariableName
= VariableName
;
1680 VariableDefinitionsHead
->VariableSize
= VariableSize
;
1681 CopyMem (&VariableDefinitionsHead
->Guid
, &Guid
, sizeof (EFI_GUID
));
1685 case EFI_IFR_END_FORM_SET_OP
:
1686 CurrentVariable
= 0;
1687 CurrentVariable2
= 0;