aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons/Lesson_66
diff options
context:
space:
mode:
Diffstat (limited to 'Lessons/Lesson_66')
-rw-r--r--Lessons/Lesson_66/README.md137
-rw-r--r--Lessons/Lesson_66/String1.pngbin0 -> 4896 bytes
-rw-r--r--Lessons/Lesson_66/String2.pngbin0 -> 6063 bytes
-rw-r--r--Lessons/Lesson_66/String3.pngbin0 -> 5567 bytes
-rw-r--r--Lessons/Lesson_66/String4.pngbin0 -> 5180 bytes
-rw-r--r--Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/Data.h16
-rw-r--r--Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/Form.vfr34
-rw-r--r--Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.c140
-rw-r--r--Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.inf22
-rw-r--r--Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/Strings.uni17
10 files changed, 366 insertions, 0 deletions
diff --git a/Lessons/Lesson_66/README.md b/Lessons/Lesson_66/README.md
new file mode 100644
index 0000000..b46ec49
--- /dev/null
+++ b/Lessons/Lesson_66/README.md
@@ -0,0 +1,137 @@
+Let's look at another data input VFR element - `string` (https://edk2-docs.gitbook.io/edk-ii-vfr-specification/2_vfr_description_in_bnf/211_vfr_form_definition#2.11.6.7.1-vfr-string-statement-definition)
+
+This element is intended to store `CHAR16` strings.
+
+Here is minimal code that we need to add to our VFR code. `minsize`/`maxsize` elements are mandatory for the `string` element:
+```
+string
+ varid = FormData.StringValue,
+ prompt = STRING_TOKEN(STRING_PROMPT),
+ help = STRING_TOKEN(STRING_HELP),
+ minsize = 5,
+ maxsize = 10,
+endstring;
+```
+
+Off course add new tokens to the `UefiLessonsPkg/HIIFormDataElements/Strings.uni`:
+```
+#string STRING_PROMPT #language en-US "String prompt"
+#string STRING_HELP #language en-US "String help"
+```
+
+As for our `UEFI_VARIABLE_STRUCTURE`, we need to add array of `UINT16` elements with a size at least of `maxsize`:
+```
+typedef struct {
+ UINT8 CheckboxValue;
+ UINT16 NumericValue;
+ UINT16 StringValue[10];
+} UEFI_VARIABLE_STRUCTURE;
+```
+
+If array size is lower than `maxsize` EDKII build system would fail:
+```
+ERROR 12288: String MaxSize can't be larger than the max number of elements in string array.
+```
+
+Don't forget to delete old UEFI Variable before loading our updated driver:
+```
+Shell> dmpstore -guid 531bc507-9191-4fa2-9446-b844e35dd12a -d
+Delete variable '531BC507-9191-4FA2-9446-B844E35DD12A:FormData': Success
+Shell> load fs0:HIIFormDataElements.efi
+```
+
+By default element looks like this:
+![String1](String1.png?raw=true "String1")
+
+As we have `minsize` string limit, it is not possible to enter string smaller than 5 characters:
+![String2](String2.png?raw=true "String2")
+
+It is also not possible to enter string longer than 10 characters. HII simply won't allow you to type symbols beyond the limit:
+![String3](String3.png?raw=true "String3")
+
+But if everything is in limits, you can successfully save data:
+![String4](String4.png?raw=true "String4")
+
+After that you can check our UEFI variable storage:
+```
+Shell> dmpstore -guid 531bc507-9191-4fa2-9446-b844e35dd12a
+Variable NV+BS '531BC507-9191-4FA2-9446-B844E35DD12A:FormData' DataSize = 0x17
+ 00000000: 00 00 00 55 00 45 00 46-00 49 00 2D 00 4C 00 65 *...U.E.F.I.-.L.e*
+ 00000010: 00 73 00 73 00 6F 00 *.s.s.o.*
+```
+
+As you can see the string doesn't contain `\0` terminating symbol. So for simplicity maybe it is better to declare array size one element larger than the value in the VFR `maxsize` field.
+ field (i.e. `CHAR16 StringValue[11]`).
+
+This way it would be easier to parse string field from our UEFI variable:
+```
+Shell> dmpstore -guid 531bc507-9191-4fa2-9446-b844e35dd12a
+Variable NV+BS '531BC507-9191-4FA2-9446-B844E35DD12A:FormData' DataSize = 0x19
+ 00000000: 00 00 00 55 00 45 00 46-00 49 00 2D 00 4C 00 65 *...U.E.F.I.-.L.e*
+ 00000010: 00 73 00 73 00 6F 00 00-00 *.s.s.o...*
+```
+
+# MULTI_LINE
+
+VFR specification defines a `MULTI_LINE` flag for the `string` element:
+```
+string
+ varid = FormData.StringValue,
+ prompt = STRING_TOKEN(STRING_PROMPT),
+ help = STRING_TOKEN(STRING_HELP),
+ flags = MULTI_LINE,
+ minsize = 5,
+ maxsize = 10,
+endstring;
+```
+
+This flag should work as a hint for the form browser that multi-line text can be allowed. But currently OVMF form broswer doesn't use this flag.
+
+# IFR
+
+You can look at IFR code `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements/DEBUG/Form.lst`:
+```
+ string
+>00000082: 1C 90 09 00 0A 00 03 00 01 00 03 00 00 05 0A 00
+ varid = FormData.StringValue,
+ prompt = STRING_TOKEN(0x0009),
+ help = STRING_TOKEN(0x000A),
+ minsize = 5,
+ maxsize = 10,
+ endstring;
+>00000092: 29 02
+```
+
+The data encodes `EFI_IFR_STRING` structure:
+```
+Summary:
+Defines the string question.
+
+Prototype:
+#define EFI_IFR_STRING_OP 0x1C
+
+typedef struct _EFI_IFR_STRING {
+ EFI_IFR_OP_HEADER Header;
+ EFI_IFR_QUESTION_HEADER Question;
+ UINT8 MinSize;
+ UINT8 MaxSize;
+ UINT8 Flags;
+} EFI_IFR_STRING;
+
+Members:
+Header The sequence that defines the type of opcode as well as the length of the opcode being defined.
+ Header.OpCode = EFI_IFR_STRING_OP.
+Question The standard question header.
+MinSize The minimum number of characters that can be accepted for this opcode.
+MaxSize The maximum number of characters that can be accepted for this opcode.
+Flags Flags which control the string editing behavior.
+
+Description:
+This creates a string question. The minimum length is MinSize and the maximum length is MaxSize
+```
+
+You can parse the data, but really there is nothing new for us.
+
+# Note
+
+At the time of this writing you can cheat EDKII build system and declare `StringValue` array with the size of 10, but with a type of `UINT8`. The code would compile, but as you can guess, you shouldn't expect anything good from this. Right now because of this error HII system would allow you to "save" form and wouldn't even complain. But as an actual value data still wouldn't be equal to the form data, HII would you suggest to save form data endlessly.
diff --git a/Lessons/Lesson_66/String1.png b/Lessons/Lesson_66/String1.png
new file mode 100644
index 0000000..2c93747
--- /dev/null
+++ b/Lessons/Lesson_66/String1.png
Binary files differ
diff --git a/Lessons/Lesson_66/String2.png b/Lessons/Lesson_66/String2.png
new file mode 100644
index 0000000..9194993
--- /dev/null
+++ b/Lessons/Lesson_66/String2.png
Binary files differ
diff --git a/Lessons/Lesson_66/String3.png b/Lessons/Lesson_66/String3.png
new file mode 100644
index 0000000..04e160a
--- /dev/null
+++ b/Lessons/Lesson_66/String3.png
Binary files differ
diff --git a/Lessons/Lesson_66/String4.png b/Lessons/Lesson_66/String4.png
new file mode 100644
index 0000000..2e8b7fd
--- /dev/null
+++ b/Lessons/Lesson_66/String4.png
Binary files differ
diff --git a/Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/Data.h b/Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/Data.h
new file mode 100644
index 0000000..80bd3dc
--- /dev/null
+++ b/Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/Data.h
@@ -0,0 +1,16 @@
+#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];
+} UEFI_VARIABLE_STRUCTURE;
+#pragma pack()
+
+#endif
diff --git a/Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/Form.vfr b/Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/Form.vfr
new file mode 100644
index 0000000..42affd4
--- /dev/null
+++ b/Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/Form.vfr
@@ -0,0 +1,34 @@
+#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;
+ endform;
+endformset;
diff --git a/Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.c b/Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.c
new file mode 100644
index 0000000..5920b58
--- /dev/null
+++ b/Lessons/Lesson_66/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_66/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.inf b/Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements.inf
new file mode 100644
index 0000000..b9c0652
--- /dev/null
+++ b/Lessons/Lesson_66/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_66/UefiLessonsPkg/HIIFormDataElements/Strings.uni b/Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/Strings.uni
new file mode 100644
index 0000000..4e283e1
--- /dev/null
+++ b/Lessons/Lesson_66/UefiLessonsPkg/HIIFormDataElements/Strings.uni
@@ -0,0 +1,17 @@
+//
+// 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"