Skip to content

Latest commit

 

History

History

Lesson_68

oneof element

oneof element allows to select an option from the predefined set (https://edk2-docs.gitbook.io/edk-ii-vfr-specification/2_vfr_description_in_bnf/211_vfr_form_definition#2.11.6.6.2-vfr-oneof-statement-definition)

Add the folowing code to the UefiLessonsPkg/HIIFormDataElements/Form.vfr

oneof
  varid = FormData.OneOfValue,
  prompt = STRING_TOKEN(ONEOF_PROMPT),
  help = STRING_TOKEN(ONEOF_HELP),
  option text = STRING_TOKEN(ONEOF_OPTION1), value = 0x00, flags = DEFAULT;
  option text = STRING_TOKEN(ONEOF_OPTION2), value = 0x33, flags = 0;
  option text = STRING_TOKEN(ONEOF_OPTION3), value = 0x55, flags = 0;
endoneof;

Add new string tokens to the UefiLessonsPkg/HIIFormDataElements/Strings.uni:

#string ONEOF_PROMPT           #language en-US  "OneOf list prompt"
#string ONEOF_HELP             #language en-US  "OneOf list help"
#string ONEOF_OPTION1          #language en-US  "OneOf list option 1"
#string ONEOF_OPTION2          #language en-US  "OneOf list option 2"
#string ONEOF_OPTION3          #language en-US  "OneOf list option 3"

As for data, add this to the UefiLessonsPkg/HIIFormDataElements/Data.h:

typedef struct {
  ...
  UINT8 OneOf;
} UEFI_VARIABLE_STRUCTURE;

Once you load the form, you would get:

OneOf1

You can select one of the available options:

OneOf2

If you select the option 2:

OneOf3

The variable field would get the value 0x33. If you want to, you can verify it with the dmpstore command.

IFR

IFR code would look like this (Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements/DEBUG/Form.lst):

    oneof
>000000B4: 05 91 0F 00 10 00 06 00 01 00 20 00 00 10 00 55 00
      varid = FormData.OneOfValue,
      prompt = STRING_TOKEN(0x000F),
      help = STRING_TOKEN(0x0010),
      option text = STRING_TOKEN(0x0011), value = 0x00, flags = DEFAULT;
>000000C5: 09 07 11 00 10 00 00
      option text = STRING_TOKEN(0x0012), value = 0x33, flags = 0;
>000000CC: 09 07 12 00 00 00 33
      option text = STRING_TOKEN(0x0013), value = 0x55, flags = 0;
>000000D3: 09 07 13 00 00 00 55
    endoneof;
>000000DA: 29 02

The first opcodes are:

EFI_IFR_ONE_OF

Summary:
Creates a select-one-of question.

Prototype:

#define EFI_IFR_ONE_OF_OP 0x05

typedef struct _EFI_IFR_ONE_OF {
 EFI_IFR_OP_HEADER Header;
 EFI_IFR_QUESTION_HEADER Question;
 UINT8 Flags;
 union {
 struct {
 UINT8 MinValue;
 UINT8 MaxValue;
 UINT8 Step;
 } u8;
 struct {
 UINT16 MinValue;
 UINT16 MaxValue;
 UINT16 Step;
 } u16;
 struct {
 UINT32 MinValue;
 UINT32 MaxValue;
 UINT32 Step;
 } u32;
 struct {
 UINT64 MinValue;
 UINT64 MaxValue;
 UINT64 Step;
 } u64;
 } data;
} EFI_IFR_ONE_OF;

Members:
Header 		The sequence that defines the type of opcode as well as the length of the opcode being defined.
		Header.OpCode = EFI_IFR_ONE_OF_OP.
Question 	The standard question header.
Flags 		Specifies flags related to the numeric question.
MinValue 	The minimum value to be accepted by the browser for this opcode.
		The size of the data field may vary from 8 to 64 bits, depending on the size specified in Flags
MaxValue 	The maximum value to be accepted by the browser for this opcode.
		The size of the data field may vary from 8 to 64 bits, depending on the size specified in Flags
Step 		Defines the amount to increment or decrement the value each time a user requests a value change.
		If the step value is 0, then the input mechanism for the numeric value is to be free-form
		and require the user to type in the actual value.
		The size of the data field may vary from 8 to 64 bits, depending on the size specified in Flags

Description:
This opcode creates a select-on-of object, where the user must select from one of the nested options.
This is identical to EFI_IFR_NUMERIC.

And here is a definition for the options opcodes:

EFI_IFR_ONE_OF_OPTION

Summary:
Creates a pre-defined option for a question.

Prototype:

#define EFI_IFR_ONE_OF_OPTION_OP 0x09

typedef struct _EFI_IFR_ONE_OF_OPTION {
 EFI_IFR_OP_HEADER Header;
 EFI_STRING_ID Option;
 UINT8 Flags;
 UINT8 Type;
 EFI_IFR_TYPE_VALUE Value;
} EFI_IFR_ONE_OF_OPTION;

Members:
Header	 The sequence that defines the type of opcode as well as the length of the opcode being defined.
	 Header.OpCode = EFI_IFR_ONE_OF_OPTION_OP.
Option   The string token reference to the option description string for this particular opcode.
Flags    Specifies the flags associated with the current option (EFI_IFR_OPTION_x)
Type 	 Specifies the type of the option’s value (See EFI_IFR_TYPE)
Value 	 The union of all of the different possible values. The actual contents (and size)
	 of the field depends on Type.

Description says that the content of the Value field is dependent on the value of the Type field. Here are all the possible value types with comments of their type flags:

typedef union {
 UINT8 u8;             // EFI_IFR_TYPE_NUM_SIZE_8
 UINT16 u16;           // EFI_IFR_TYPE_NUM_SIZE_16
 UINT32 u32;           // EFI_IFR_TYPE_NUM_SIZE_32
 UINT64 u64;           // EFI_IFR_TYPE_NUM_SIZE_64
 BOOLEAN b;            // EFI_IFR_TYPE_BOOLEAN
 EFI_HII_TIME time;    // EFI_IFR_TYPE_TIME
 EFI_HII_DATE date;    // EFI_IFR_TYPE_DATE
 EFI_STRING_ID string; // EFI_IFR_TYPE_STRING, EFI_IFR_TYPE_ACTION
 EFI_HII_REF ref;      // EFI_IFR_TYPE_REF
 // UINT8 buffer[];    // EFI_IFR_TYPE_BUFFER
} EFI_IFR_TYPE_VALUE;

And here are the actual values for the EFI_IFR_TYPE_x defines:

#define EFI_IFR_TYPE_NUM_SIZE_8 	0x00
#define EFI_IFR_TYPE_NUM_SIZE_16 	0x01
#define EFI_IFR_TYPE_NUM_SIZE_32 	0x02
#define EFI_IFR_TYPE_NUM_SIZE_64 	0x03
#define EFI_IFR_TYPE_BOOLEAN 		0x04
#define EFI_IFR_TYPE_TIME 		0x05
#define EFI_IFR_TYPE_DATE 		0x06
#define EFI_IFR_TYPE_STRING 		0x07
#define EFI_IFR_TYPE_OTHER 		0x08
#define EFI_IFR_TYPE_UNDEFINED 		0x09
#define EFI_IFR_TYPE_ACTION 		0x0A
#define EFI_IFR_TYPE_BUFFER 		0x0B
#define EFI_IFR_TYPE_REF 		0x0C

In our structure we've declared data as UINT8 OneOf. Therefore compiler automatically have deducted our type flag as EFI_IFR_TYPE_NUM_SIZE_8. If we change that to UINT16 OneOf, compiler would change the type field value to the EFI_IFR_TYPE_NUM_SIZE_16.

Compare this output with the one that we had before:

    oneof
>000000B4: 05 94 0F 00 10 00 06 00 01 00 20 00 00 11 00 00 55 00 00 00
      varid = FormData.OneOfValue,
      prompt = STRING_TOKEN(0x000F),
      help = STRING_TOKEN(0x0010),
      option text = STRING_TOKEN(0x0011), value = 0x00, flags = DEFAULT;
>000000C8: 09 08 11 00 11 01 00 00
      option text = STRING_TOKEN(0x0012), value = 0x33, flags = 0;
>000000D0: 09 08 12 00 01 01 33 00
      option text = STRING_TOKEN(0x0013), value = 0x55, flags = 0;
>000000D8: 09 08 13 00 01 01 55 00
    endoneof;
>000000E0: 29 02

Although EFI_IFR_TYPE_VALUE can take many values besides numeric if you try to set its type to the EFI_HII_DATE OneOfValue for example, you would get an error:

ERROR 12288: OneOf question only support UINT8, UINT16, UINT32 and UINT64 data type

So only subtype of EFI_IFR_TYPE_VALUE is supported.

orderedlist element

Another element with options is the orderedlist element (https://edk2-docs.gitbook.io/edk-ii-vfr-specification/2_vfr_description_in_bnf/211_vfr_form_definition#2.11.6.8-vfr-orderedlist-statement-definition)

Add this to the UefiLessonsPkg/HIIFormDataElements/Form.vfr:

orderedlist
  varid = FormData.OrderedListValue,
  prompt = STRING_TOKEN(ORDERED_LIST_PROMPT),
  help = STRING_TOKEN(ORDERED_LIST_HELP),
  option text = STRING_TOKEN(ORDERED_LIST_OPTION1), value = 0x0A, flags = 0;
  option text = STRING_TOKEN(ORDERED_LIST_OPTION2), value = 0x0B, flags = 0;
  option text = STRING_TOKEN(ORDERED_LIST_OPTION3), value = 0x0C, flags = 0;
endlist;

Add strings to the UefiLessonsPkg/HIIFormDataElements/Strings.uni:

#string ORDERED_LIST_PROMPT    #language en-US  "Ordered list prompt"
#string ORDERED_LIST_HELP      #language en-US  "Ordered list help"
#string ORDERED_LIST_OPTION1   #language en-US  "Ordered list option 1"
#string ORDERED_LIST_OPTION2   #language en-US  "Ordered list option 2"
#string ORDERED_LIST_OPTION3   #language en-US  "Ordered list option 3"

If we have 3 options, we need to declare array of 3 elements. Let's declare them as UINT8:

typedef struct {
  ...
  UINT8 OrderedListValue[3];
} UEFI_VARIABLE_STRUCTURE;

On load our form would look like this:

Orderedlist1

If you select the element:

Orderedlist2

You can change its order by moving it up or down with the help of + and - keys:

Orderedlist3

Change order to 2 1 3 and save it with F10:

Orderedlist4

This would get the following data in the OrderedListValue field of our UEFI variable:

0B 0A 0C

IFR

Let's look at the IFR code (Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements/DEBUG/Form.lst):

    orderedlist
>000000DC: 23 8F 14 00 15 00 07 00 01 00 21 00 00 03 00
      varid = FormData.OrderedListValue,
      prompt = STRING_TOKEN(0x0014),
      help = STRING_TOKEN(0x0015),
      option text = STRING_TOKEN(0x0016), value = 0x0A, flags = 0;
>000000EB: 09 07 16 00 00 00 0A
      option text = STRING_TOKEN(0x0017), value = 0x0B, flags = 0;
>000000F2: 09 07 17 00 00 00 0B
      option text = STRING_TOKEN(0x0018), value = 0x0C, flags = 0;
>000000F9: 09 07 18 00 00 00 0C
    endlist;
>00000100: 29 02

First code element is EFI_IFR_ORDERED_LIST:

EFI_IFR_ORDERED_LIST

Summary:
Creates a set question using an ordered list.

#define EFI_IFR_ORDERED_LIST_OP 0x23

typedef struct _EFI_IFR_ORDERED_LIST {
 EFI_IFR_OP_HEADER Header;
 EFI_IFR_QUESTION_HEADER Question;
 UINT8 MaxContainers;
 UINT8 Flags;
} EFI_IFR_ORDERED_LIST;

Members:
Header 		The byte sequence that defines the type of opcode as well as the length of the opcode being defined.
		Header.OpCode = EFI_IFR_ORDERED_LIST_OP.
Question 	The standard question header.
MaxContainers 	The maximum number of entries for which this tag will maintain an order.
		This value also identifies the size of the storage associated with this tag’s ordering array.
Flags		A bit-mask that determines which unique settings are active for this opcode.

Description:
Create an ordered list question in the current form. One thing to note is that valid values for the options
in ordered lists should never be a 0.

If you match data to the fields, you would get the following data for the new fields:

UINT8 MaxContainers;	// 0x03
UINT8 Flags;		// 0x00

Everything is in order, our element has 3 options, and therefore MaxContainers=0x03.

If you look at the options IFR code you could see that the options are encoded with the same opcode EFI_IFR_ONE_OF_OPTION that was used in the oneof element.

Here the principle is the same. If you encode our data as UINT16 instead of UINT8

UINT16 OrderedListValue[3];

The compiler would encode options as EFI_IFR_TYPE_NUM_SIZE_16 (=UINT16) and in the storage they would look as:

0B 00 0A 00 0C 00

With the orderedlist it is even possible to use non-numeric data types. For example you can encode variable as array of dates:

EFI_HII_DATE OrderedListValue[3];

For this off course you need to change the code in VFR:

orderedlist
  varid = FormData.OrderedListValue,
  prompt = STRING_TOKEN(ORDERED_LIST_PROMPT),
  help = STRING_TOKEN(ORDERED_LIST_HELP),
  option text = STRING_TOKEN(ORDERED_LIST_OPTION1), value = 2021/7/4, flags = 0;
  option text = STRING_TOKEN(ORDERED_LIST_OPTION2), value = 2022/8/5, flags = 0;
  option text = STRING_TOKEN(ORDERED_LIST_OPTION3), value = 2023/9/6, flags = 0;
endlist;

If you parse IFR data for such code, you could see that every option is encoded with #define EFI_IFR_TYPE_DATE 0x06 type:

    orderedlist
>000000DC: 23 8F 14 00 15 00 07 00 01 00 21 00 00 0C 00
      varid = FormData.OrderedListValue,
      prompt = STRING_TOKEN(0x0014),
      help = STRING_TOKEN(0x0015),
      option text = STRING_TOKEN(0x0016), value = 2021/7/4, flags = 0;
>000000EB: 09 0A 16 00 06 06 E5 07 07 04
      option text = STRING_TOKEN(0x0017), value = 2022/8/5, flags = 0;
>000000F5: 09 0A 17 00 06 06 E6 07 08 05
      option text = STRING_TOKEN(0x0018), value = 2023/9/6, flags = 0;
>000000FF: 09 0A 18 00 06 06 E7 07 09 06
    endlist;
>00000109: 29 02

If the data array has a size lower than amount of available options, everything would compile, but in the HII, you would see only the first array size options. For example UINT8 OrderedListValue[2] would result to:

Orderedlistr5