aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons/Lesson_68
diff options
context:
space:
mode:
Diffstat (limited to 'Lessons/Lesson_68')
-rw-r--r--Lessons/Lesson_68/OneOf1.pngbin0 -> 6361 bytes
-rw-r--r--Lessons/Lesson_68/OneOf2.pngbin0 -> 7026 bytes
-rw-r--r--Lessons/Lesson_68/OneOf3.pngbin0 -> 6359 bytes
-rw-r--r--Lessons/Lesson_68/Orderedlist1.pngbin0 -> 7874 bytes
-rw-r--r--Lessons/Lesson_68/Orderedlist2.pngbin0 -> 7833 bytes
-rw-r--r--Lessons/Lesson_68/Orderedlist3.pngbin0 -> 7772 bytes
-rw-r--r--Lessons/Lesson_68/Orderedlist4.pngbin0 -> 7896 bytes
-rw-r--r--Lessons/Lesson_68/Orderedlist5.pngbin0 -> 7435 bytes
-rw-r--r--Lessons/Lesson_68/README.md370
-rw-r--r--Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Data.h20
-rw-r--r--Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Form.vfr72
-rw-r--r--Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.c140
-rw-r--r--Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.inf22
-rw-r--r--Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Strings.uni31
14 files changed, 655 insertions, 0 deletions
diff --git a/Lessons/Lesson_68/OneOf1.png b/Lessons/Lesson_68/OneOf1.png
new file mode 100644
index 0000000..2ad8398
--- /dev/null
+++ b/Lessons/Lesson_68/OneOf1.png
Binary files differ
diff --git a/Lessons/Lesson_68/OneOf2.png b/Lessons/Lesson_68/OneOf2.png
new file mode 100644
index 0000000..acc0a7a
--- /dev/null
+++ b/Lessons/Lesson_68/OneOf2.png
Binary files differ
diff --git a/Lessons/Lesson_68/OneOf3.png b/Lessons/Lesson_68/OneOf3.png
new file mode 100644
index 0000000..5ca7322
--- /dev/null
+++ b/Lessons/Lesson_68/OneOf3.png
Binary files differ
diff --git a/Lessons/Lesson_68/Orderedlist1.png b/Lessons/Lesson_68/Orderedlist1.png
new file mode 100644
index 0000000..37520ca
--- /dev/null
+++ b/Lessons/Lesson_68/Orderedlist1.png
Binary files differ
diff --git a/Lessons/Lesson_68/Orderedlist2.png b/Lessons/Lesson_68/Orderedlist2.png
new file mode 100644
index 0000000..a1df76a
--- /dev/null
+++ b/Lessons/Lesson_68/Orderedlist2.png
Binary files differ
diff --git a/Lessons/Lesson_68/Orderedlist3.png b/Lessons/Lesson_68/Orderedlist3.png
new file mode 100644
index 0000000..8400673
--- /dev/null
+++ b/Lessons/Lesson_68/Orderedlist3.png
Binary files differ
diff --git a/Lessons/Lesson_68/Orderedlist4.png b/Lessons/Lesson_68/Orderedlist4.png
new file mode 100644
index 0000000..a4f6d4b
--- /dev/null
+++ b/Lessons/Lesson_68/Orderedlist4.png
Binary files differ
diff --git a/Lessons/Lesson_68/Orderedlist5.png b/Lessons/Lesson_68/Orderedlist5.png
new file mode 100644
index 0000000..22d6527
--- /dev/null
+++ b/Lessons/Lesson_68/Orderedlist5.png
Binary files differ
diff --git a/Lessons/Lesson_68/README.md b/Lessons/Lesson_68/README.md
new file mode 100644
index 0000000..cdd606f
--- /dev/null
+++ b/Lessons/Lesson_68/README.md
@@ -0,0 +1,370 @@
+# `oneof` element
+
+`oneof` element allows to select on 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 get:
+
+![OneOf1](OneOf1.png?raw=true "OneOf1")
+
+You can select one of the available options:
+
+![OneOf2](OneOf2.png?raw=true "OneOf2")
+
+If you select the option 2:
+
+![OneOf3](OneOf3.png?raw=true "OneOf3")
+
+The variable field would get the value `0x33`. If you want to, you can verify it with `dmpstore`.
+
+## 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 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 form looks like this:
+
+![Orderedlist1](OrderedList1.png?raw=true "OrderedList1")
+
+If you select the element:
+
+![Orderedlist2](OrderedList2.png?raw=true "OrderedList2")
+
+You can change order by selecting an option and moving it up or down with the help of `+` and `-` keys:
+
+![Orderedlist3](OrderedList3.png?raw=true "OrderedList3")
+
+Change order to `2 1 3` and save it with `F10`:
+
+![Orderedlist4](OrderedList4.png?raw=true "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 element if `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 `oneof` element.
+
+Therefore 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];
+```
+
+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 now, 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 option, 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](OrderedList5.png?raw=true "OrderedList5")
diff --git a/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Data.h b/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Data.h
new file mode 100644
index 0000000..ad5689a
--- /dev/null
+++ b/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Data.h
@@ -0,0 +1,20 @@
+#ifndef _DATA_H_
+#define _DATA_H_
+
+#define FORMSET_GUID {0x531bc507, 0x9191, 0x4fa2, {0x94, 0x46, 0xb8, 0x44, 0xe3, 0x5d, 0xd1, 0x2a}}
+
+#define UEFI_VARIABLE_STRUCTURE_NAME L"FormData"
+
+#pragma pack(1)
+typedef struct {
+ UINT8 CheckboxValue;
+ UINT16 NumericValue;
+ CHAR16 StringValue[11];
+ EFI_HII_DATE DateValue;
+ EFI_HII_TIME TimeValue;
+ UINT8 OneOfValue;
+ UINT8 OrderedListValue[3];
+} UEFI_VARIABLE_STRUCTURE;
+#pragma pack()
+
+#endif
diff --git a/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Form.vfr b/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Form.vfr
new file mode 100644
index 0000000..cd275a6
--- /dev/null
+++ b/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Form.vfr
@@ -0,0 +1,72 @@
+#include <Uefi/UefiMultiPhase.h>
+#include "Data.h"
+
+formset
+ guid = FORMSET_GUID,
+ title = STRING_TOKEN(FORMSET_TITLE),
+ help = STRING_TOKEN(FORMSET_HELP),
+
+ efivarstore UEFI_VARIABLE_STRUCTURE,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ name = FormData,
+ guid = FORMSET_GUID;
+
+ form
+ formid = 1,
+ title = STRING_TOKEN(FORMID1_TITLE);
+
+ checkbox
+ varid = FormData.CheckboxValue,
+ prompt = STRING_TOKEN(CHECKBOX_PROMPT),
+ help = STRING_TOKEN(CHECKBOX_HELP),
+ endcheckbox;
+
+ numeric
+ varid = FormData.NumericValue,
+ prompt = STRING_TOKEN(NUMERIC_PROMPT),
+ help = STRING_TOKEN(NUMERIC_HELP),
+ flags = NUMERIC_SIZE_2 | DISPLAY_UINT_HEX,
+ minimum = 0x1234,
+ maximum = 0xaa55,
+ step = 2,
+ endnumeric;
+
+ string
+ varid = FormData.StringValue,
+ prompt = STRING_TOKEN(STRING_PROMPT),
+ help = STRING_TOKEN(STRING_HELP),
+ minsize = 5,
+ maxsize = 10,
+ endstring;
+
+ date
+ varid = FormData.DateValue,
+ prompt = STRING_TOKEN(DATE_PROMPT),
+ help = STRING_TOKEN(DATE_HELP),
+ enddate;
+
+ time
+ varid = FormData.TimeValue,
+ prompt = STRING_TOKEN(TIME_PROMPT),
+ help = STRING_TOKEN(TIME_HELP),
+ endtime;
+
+ 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;
+
+ 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;
+ endform;
+endformset;
diff --git a/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.c b/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.c
new file mode 100644
index 0000000..5920b58
--- /dev/null
+++ b/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.c
@@ -0,0 +1,140 @@
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include "Data.h"
+
+extern UINT8 FormBin[];
+
+#pragma pack(1)
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+#pragma pack()
+
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+
+EFI_HII_HANDLE mHiiHandle = NULL;
+EFI_HANDLE mDriverHandle = NULL;
+EFI_STRING UEFIVariableName = UEFI_VARIABLE_STRUCTURE_NAME;
+
+
+EFI_STATUS
+EFIAPI
+HIIFormDataElementsUnload (
+ EFI_HANDLE ImageHandle
+ )
+{
+ if (mHiiHandle != NULL)
+ HiiRemovePackages(mHiiHandle);
+
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ UEFI_VARIABLE_STRUCTURE EfiVarstore;
+
+ BufferSize = sizeof(UEFI_VARIABLE_STRUCTURE);
+ Status = gRT->GetVariable(
+ UEFIVariableName,
+ &mHiiVendorDevicePath.VendorDevicePath.Guid,
+ NULL,
+ &BufferSize,
+ &EfiVarstore);
+ if (!EFI_ERROR(Status)) {
+ Status = gRT->SetVariable(
+ UEFIVariableName,
+ &mHiiVendorDevicePath.VendorDevicePath.Guid,
+ 0,
+ 0,
+ NULL);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error! Can't delete variable! %r\n", Status);
+ }
+ }
+
+ Status = gBS->UninstallMultipleProtocolInterfaces(
+ mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ NULL
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+HIIFormDataElementsEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ Status = gBS->InstallMultipleProtocolInterfaces(
+ &mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UINTN BufferSize;
+ UEFI_VARIABLE_STRUCTURE EfiVarstore;
+ BufferSize = sizeof(UEFI_VARIABLE_STRUCTURE);
+ Status = gRT->GetVariable (
+ UEFIVariableName,
+ &mHiiVendorDevicePath.VendorDevicePath.Guid,
+ NULL,
+ &BufferSize,
+ &EfiVarstore);
+ if (EFI_ERROR(Status)) {
+ ZeroMem(&EfiVarstore, sizeof(EfiVarstore));
+ Status = gRT->SetVariable(
+ UEFIVariableName,
+ &mHiiVendorDevicePath.VendorDevicePath.Guid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof(EfiVarstore),
+ &EfiVarstore);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error! Can't create variable! %r\n", Status);
+ }
+ }
+
+ mHiiHandle = HiiAddPackages(
+ &gEfiCallerIdGuid,
+ mDriverHandle,
+ HIIFormDataElementsStrings,
+ FormBin,
+ NULL
+ );
+ if (mHiiHandle == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.inf b/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.inf
new file mode 100644
index 0000000..b9c0652
--- /dev/null
+++ b/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.inf
@@ -0,0 +1,22 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = HIIFormDataElements
+ FILE_GUID = ab971f73-f582-4f90-a48d-88ff7c884bd9
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = HIIFormDataElementsEntryPoint
+ UNLOAD_IMAGE = HIIFormDataElementsUnload
+
+[Sources]
+ HIIFormDataElements.c
+ Strings.uni
+ Form.vfr
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiLib
+ HiiLib
diff --git a/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Strings.uni b/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Strings.uni
new file mode 100644
index 0000000..6429f55
--- /dev/null
+++ b/Lessons/Lesson_68/UefiLessonsPkg/HIIFormDataElements/Strings.uni
@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com>
+//
+// SPDX-License-Identifier: MIT
+//
+
+#langdef en-US "English"
+
+#string FORMSET_TITLE #language en-US "Simple Formset"
+#string FORMSET_HELP #language en-US "This is a very simple formset"
+#string FORMID1_TITLE #language en-US "Simple Form"
+#string CHECKBOX_PROMPT #language en-US "Checkbox prompt"
+#string CHECKBOX_HELP #language en-US "Checkbox help"
+#string NUMERIC_PROMPT #language en-US "Numeric prompt"
+#string NUMERIC_HELP #language en-US "Numeric help"
+#string STRING_PROMPT #language en-US "String prompt"
+#string STRING_HELP #language en-US "String help"
+#string DATE_PROMPT #language en-US "Date prompt"
+#string DATE_HELP #language en-US "Date help"
+#string TIME_PROMPT #language en-US "Time prompt"
+#string TIME_HELP #language en-US "Time help"
+#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"
+#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"