aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonstantin Aladyshev <aladyshev22@gmail.com>2022-10-03 12:16:57 +0300
committerKonstantin Aladyshev <aladyshev22@gmail.com>2022-10-03 12:16:57 +0300
commit6fb148714b27142dbf39569d4d094091ca2224a7 (patch)
tree0823d478f3237c7551fa9afd59908971c5cbb0b4
parentb6be6079143a13f77c1c891a85a4f2128ad72063 (diff)
downloadUEFI-Lessons-6fb148714b27142dbf39569d4d094091ca2224a7.tar.gz
UEFI-Lessons-6fb148714b27142dbf39569d4d094091ca2224a7.tar.bz2
UEFI-Lessons-6fb148714b27142dbf39569d4d094091ca2224a7.zip
Finish Callback() lesson
Signed-off-by: Konstantin Aladyshev <aladyshev22@gmail.com>
-rw-r--r--Lessons_uncategorized/Lesson_Varstore_5/README.md64
-rw-r--r--Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Data.h20
-rw-r--r--Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Form.vfr107
-rw-r--r--Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/HIIFormDataElementsVarstore.c323
-rw-r--r--Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/HIIFormDataElementsVarstore.inf34
-rw-r--r--Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Strings.uni46
-rw-r--r--README.md1
7 files changed, 567 insertions, 28 deletions
diff --git a/Lessons_uncategorized/Lesson_Varstore_5/README.md b/Lessons_uncategorized/Lesson_Varstore_5/README.md
index 43a1b94..f3c9f23 100644
--- a/Lessons_uncategorized/Lesson_Varstore_5/README.md
+++ b/Lessons_uncategorized/Lesson_Varstore_5/README.md
@@ -14,7 +14,7 @@ The `EFI_IFR_FLAG_CALLBACK` is one of the flags for the `EFI_IFR_QUESTION_HEADER
#define EFI_IFR_FLAG_RECONNECT_REQUIRED 0x40
#define EFI_IFR_FLAG_OPTIONS_ONLY 0x80
```
-The `EFI_IFR_QUESTION_HEADER` is a structure present in the IFR code of all our data elements:
+The `EFI_IFR_QUESTION_HEADER` in turn is a structure present in the IFR code of all our data elements:
```
EFI_IFR_CHECKBOX - checkbox
EFI_IFR_NUMERIC - numeric
@@ -79,7 +79,7 @@ Action. Depending on the action, the browser may also pass the question value us
Upon return, the callback function may specify the desired browser action.
```
-To better understand when and how this function is called let's add a debug statement that would print incoming arguments like we did with `RouteConfig()` and `ExtractConfig()`. But for that we need to understand this arguments first.
+To better understand when and how this function is called let's add a debug statement that would print incoming arguments like we did with `RouteConfig()` and `ExtractConfig()`. But first let's try to understand what all these arguments mean.
## `EFI_BROWSER_ACTION Action`
@@ -87,18 +87,18 @@ This argument describes an operation that is currently performed by the browser.
```cpp
typedef UINTN EFI_BROWSER_ACTION;
-#define EFI_BROWSER_ACTION_CHANGING 0
-#define EFI_BROWSER_ACTION_CHANGED 1
-#define EFI_BROWSER_ACTION_RETRIEVE 2
-#define EFI_BROWSER_ACTION_FORM_OPEN 3
-#define EFI_BROWSER_ACTION_FORM_CLOSE 4
-#define EFI_BROWSER_ACTION_SUBMITTED 5
-#define EFI_BROWSER_ACTION_DEFAULT_STANDARD 0x1000
-#define EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING 0x1001
-#define EFI_BROWSER_ACTION_DEFAULT_SAFE 0x1002
-#define EFI_BROWSER_ACTION_DEFAULT_PLATFORM 0x2000
-#define EFI_BROWSER_ACTION_DEFAULT_HARDWARE 0x3000
-#define EFI_BROWSER_ACTION_DEFAULT_FIRMWARE 0x4000
+#define EFI_BROWSER_ACTION_CHANGING 0 // Called after the user have changed the element value, but before the browser updated display
+#define EFI_BROWSER_ACTION_CHANGED 1 // Called after the user have changed the element value, after the browser updated display
+#define EFI_BROWSER_ACTION_RETRIEVE 2 // Called after the browser has read the value, but before displayed it
+#define EFI_BROWSER_ACTION_FORM_OPEN 3 // Called on form open before retrieve
+#define EFI_BROWSER_ACTION_FORM_CLOSE 4 // Called on form exit
+#define EFI_BROWSER_ACTION_SUBMITTED 5 // Called after submit
+#define EFI_BROWSER_ACTION_DEFAULT_STANDARD 0x1000 // Called on setting standard default (default value is equal 0x0000)
+#define EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING 0x1001 // Called on setting manufacture default (default value is equal 0x0001)
+#define EFI_BROWSER_ACTION_DEFAULT_SAFE 0x1002 // Called on setting safe defaults (default value is equal 0x0002)
+#define EFI_BROWSER_ACTION_DEFAULT_PLATFORM 0x2000 // Called on setting platform defaults (default values in range 0x4000-0x7fff)
+#define EFI_BROWSER_ACTION_DEFAULT_HARDWARE 0x3000 // Called on setting hardware defaults (default values in range 0x8000-0xbfff)
+#define EFI_BROWSER_ACTION_DEFAULT_FIRMWARE 0x4000 // Called on setting firmware defaults (default values in range 0xc000-0xffff)
```
On each of these operations the Form Browser calls `Callback()` function for each of the form elements with the `EFI_IFR_FLAG_CALLBACK` flag.
@@ -145,12 +145,13 @@ typedef UINT16 EFI_QUESTION_ID;
```
It is just a `UINT16` value identificator to indicate for which of the form elements the `Callback()` function is called.
+It is possible to explicitly set values for question id's of your form elements with the VFR `questionid` keyword. If you don't do it, the `VfrCompiler` will implicitly assign unique question identifiers to all the form elements without it. The numbering in this case starts from `0x0001`.
## `UINT8 Type` and `EFI_IFR_TYPE_VALUE *Value`
The Form Browser also sends an actual form element data to the `Callback()` function.
-But each element store the data in it's own type. Therefore the Form Browser in one argument send the type of value [https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiInternalFormRepresentation.h](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiInternalFormRepresentation.h):
+But each element store the data in it's own type. Therefore the Form Browser in one argument sends the type of value [https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiInternalFormRepresentation.h](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiInternalFormRepresentation.h):
```
//
// Types of the option's value.
@@ -169,7 +170,7 @@ But each element store the data in it's own type. Therefore the Form Browser in
#define EFI_IFR_TYPE_BUFFER 0x0B
#define EFI_IFR_TYPE_REF 0x0C
```
-In in another argument the actual value as a union type:
+And in in another argument it sends the actual value as a union type:
```
typedef union {
UINT8 u8;
@@ -185,8 +186,7 @@ typedef union {
} EFI_IFR_TYPE_VALUE;
```
-Therefore to get the value we first look at the `UINT8 Type` argument and then use the necessary type on the `EFI_IFR_TYPE_VALUE` union.
-
+Therefore to get the actual value we first look at the `UINT8 Type` argument and then use the necessary type on the `EFI_IFR_TYPE_VALUE` union. Below I've written two functions: `TypeToStr` simply prints a type of the callback element, and `DebugCallbackValue` prints an element value based on it's type:
```cpp
EFI_STRING TypeToStr(UINT8 Type)
{
@@ -279,7 +279,7 @@ Callback (
}
```
-Besides the `Callback()` let's add the `DEBUG` statements to the `RouteConfig()` and `ExtractConfig()` function as well. This way we will know the order of how the Form Browser calls out functions:
+Besides the `Callback()` let's add the `DEBUG` statements to the `RouteConfig()` and `ExtractConfig()` functions as well. This way we will know the order of how the Form Browser calls our functions:
```
STATIC
EFI_STATUS
@@ -311,7 +311,10 @@ ExtractConfig (
}
```
-# Experiment
+Now it is time to test our driver. Build our driver, copy it to the shared folder and run QEMU with debug log. For the last operation you can use the first stage of the `run_gdb_ovmf.sh` script:
+```
+./run_gdb_ovmf.sh -1
+```
Load our driver to the UEFI shell.
```
@@ -333,7 +336,7 @@ Change the numeric element value to 3:
Callback: Action=EFI_BROWSER_ACTION_CHANGING, QuestionId=0x0002, Type=EFI_IFR_TYPE_NUM_SIZE_16, Value=3
Callback: Action=EFI_BROWSER_ACTION_CHANGED, QuestionId=0x0002, Type=EFI_IFR_TYPE_NUM_SIZE_16, Value=3
```
-As you see here the Form Browser doesn't call `ExtractConfig`/`RouteConfig` functions. It is the only situation when it is happening like that.
+As you know, in this case the Form Browser doesn't call `ExtractConfig`/`RouteConfig` functions. But as you see you still have control in that case since the `Callback()` code is called.
Submit the form with updated value:
```
@@ -358,19 +361,21 @@ Exit without submit
Callback: Action=EFI_BROWSER_ACTION_CHANGED, QuestionId=0x0002, Type=EFI_IFR_TYPE_NUM_SIZE_16, Value=3
Callback: Action=EFI_BROWSER_ACTION_FORM_CLOSE, QuestionId=0x0002, Type=EFI_IFR_TYPE_NUM_SIZE_16, Value=3
```
-Here you see that 2 callbacks were executed. As another experiment enter the form again, set manufacture defaults and submit them. And only then exit our form. This way the exit action would print only the `EFI_BROWSER_ACTION_FORM_CLOSE` callback:
+Here you see that 2 callbacks were executed: `EFI_BROWSER_ACTION_CHANGED` and `EFI_BROWSER_ACTION_FORM_CLOSE`. As another experiment enter the form again, set manufacture defaults and submit them. And only then exit our form. This way the exit action would print only the `EFI_BROWSER_ACTION_FORM_CLOSE` callback:
```
Callback: Action=EFI_BROWSER_ACTION_FORM_CLOSE, QuestionId=0x0002, Type=EFI_IFR_TYPE_NUM_SIZE_16, Value=8
```
-So the `EFI_BROWSER_ACTION_CHANGED` in this case is called only if an element has unsubmitted chanegs.
+So the `EFI_BROWSER_ACTION_CHANGED` in this case is called only if an element has unsubmitted changes.
# `QuestionId` and the order of callbacks
-In the last example the `QuestionId` for our element was set implicitly by the `VfrCompiler`. But it is possible to set it yourself with a help of a `quiestionid` keyword.
+In the last example the `QuestionId` for our element was set implicitly by the `VfrCompiler`. But as we've mentioned it earlier it is possible to set it yourself with a help of a `quiestionid` keyword.
For another experiment let's add `INTERACTIVE` flag to the `checkbox` and `string` elements. But set the `quiestionid` explicitly only for the `checkbox` and `numeric` elements:
```
+...
+
checkbox
varid = FormData.CheckboxValue,
questionid = 0x5555,
@@ -406,6 +411,8 @@ string
default = STRING_TOKEN(STRING_DEFAULT), defaultstore = StandardDefault,
default = STRING_TOKEN(STRING_PROMPT), defaultstore = ManufactureDefault,
endstring
+
+...
```
This would give us this output on the form open:
@@ -418,10 +425,11 @@ Callback: Action=EFI_BROWSER_ACTION_RETRIEVE, QuestionId=0x5555, Type=EFI_IFR_TY
Callback: Action=EFI_BROWSER_ACTION_RETRIEVE, QuestionId=0x4444, Type=EFI_IFR_TYPE_NUM_SIZE_16, Value=8
Callback: Action=EFI_BROWSER_ACTION_RETRIEVE, QuestionId=0x0001, Type=EFI_IFR_TYPE_STRING, Value=String pro
```
-As you see here each action is called on every interactive form element. This is true for all other cases when the action affects all the form elements.
-The calls in this case are happening not by the order of QuestionId's, but in the order of element placement in the VFR. Also as we've said it before, the `VfrCompiler` implicitly assigns `QuestionId`'s to all the form elements which don't have any explicit define for that. Even to those which don't have any `INTERACTIVE` flag. The implicit assignments start from the `0x0001` value, and this is the value that our `string` element got.
+As you see here each action is called on every interactive form element. This is true for all other cases when the action affects all the form elements. This includes all the actions except `EFI_BROWSER_ACTION_CHANGING` and `EFI_BROWSER_ACTION_CHANGED`.
+
+Another thing to point out is that the calls in the output above are happening not by the order of `QuestionId`'s, but in the order of element placement in the VFR. Also as we've said it before, the `VfrCompiler` implicitly assigns `QuestionId`'s to all the form elements which don't have any explicit setting for that. Even to those which don't have any `INTERACTIVE` flag. The implicit assignment starts from the `0x0001` value, and this is the value that our `string` element got.
-If we change `numeric` element value to 3, only `numeric` callback will be executed
+Now if we change the `numeric` element value to 3, only `numeric` callback will be executed:
```
Callback: Action=EFI_BROWSER_ACTION_CHANGING, QuestionId=0x4444, Type=EFI_IFR_TYPE_NUM_SIZE_16, Value=3
Callback: Action=EFI_BROWSER_ACTION_CHANGED, QuestionId=0x4444, Type=EFI_IFR_TYPE_NUM_SIZE_16, Value=3
@@ -434,5 +442,5 @@ Callback: Action=EFI_BROWSER_ACTION_FORM_CLOSE, QuestionId=0x4444, Type=EFI_IFR_
Callback: Action=EFI_BROWSER_ACTION_FORM_CLOSE, QuestionId=0x0001, Type=EFI_IFR_TYPE_STRING, Value=String pro
```
-I hope all of these experiment have got you some understanding about when and how the `Callback()` function is executed.
+I hope all of these experiments have got you some understanding about when and how the `Callback()` function is executed.
diff --git a/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Data.h b/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Data.h
new file mode 100644
index 0000000..c465bdd
--- /dev/null
+++ b/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Data.h
@@ -0,0 +1,20 @@
+#ifndef _DATA_H_
+#define _DATA_H_
+
+#define FORMSET_GUID {0xf8f0d09a, 0xbc44, 0x4490, {0xb1, 0x7a, 0xdd, 0xf0, 0xe5, 0xdc, 0x41, 0x7f}}
+#define DATAPATH_GUID {0xfb821964, 0xacb4, 0x437b, {0x9f, 0xe6, 0x66, 0xaa, 0x7a, 0xd7, 0xc5, 0xd8}}
+#define STORAGE_GUID {0x37807592, 0x733a, 0x4f1b, {0x95, 0x57, 0xf2, 0x2a, 0xf7, 0x43, 0xe8, 0xc2}}
+
+#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];
+} VARIABLE_STRUCTURE;
+#pragma pack()
+
+#endif
diff --git a/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Form.vfr b/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Form.vfr
new file mode 100644
index 0000000..8623d5f
--- /dev/null
+++ b/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Form.vfr
@@ -0,0 +1,107 @@
+#include <Uefi/UefiMultiPhase.h>
+#include "Data.h"
+
+formset
+ guid = FORMSET_GUID,
+ title = STRING_TOKEN(FORMSET_TITLE),
+ help = STRING_TOKEN(FORMSET_HELP),
+
+ varstore VARIABLE_STRUCTURE,
+ name = FormData,
+ guid = STORAGE_GUID;
+
+ defaultstore StandardDefault,
+ prompt = STRING_TOKEN(STANDARD_DEFAULT_PROMPT),
+ attribute = 0x0000;
+
+ defaultstore ManufactureDefault,
+ prompt = STRING_TOKEN(MFG_DEFAULT_PROMPT),
+ attribute = 0x0001;
+
+ form
+ formid = 1,
+ title = STRING_TOKEN(FORMID1_TITLE);
+
+ checkbox
+ varid = FormData.CheckboxValue,
+ questionid = 0x5555,
+ prompt = STRING_TOKEN(CHECKBOX_PROMPT),
+ help = STRING_TOKEN(CHECKBOX_HELP),
+ flags = INTERACTIVE,
+ default = TRUE, defaultstore = StandardDefault,
+ default = FALSE, defaultstore = ManufactureDefault,
+ endcheckbox;
+
+ numeric
+ name = NumericQuestion,
+ varid = FormData.NumericValue,
+ questionid = 0x4444,
+ prompt = STRING_TOKEN(NUMERIC_PROMPT),
+ help = STRING_TOKEN(NUMERIC_HELP),
+ flags = NUMERIC_SIZE_2 | DISPLAY_UINT_HEX | INTERACTIVE,
+ minimum = 0,
+ maximum = 10,
+ step = 1,
+ default = 7, defaultstore = StandardDefault,
+ default = 8, defaultstore = ManufactureDefault,
+ endnumeric;
+
+ string
+ name = StringQuestion,
+ varid = FormData.StringValue,
+ prompt = STRING_TOKEN(STRING_PROMPT),
+ help = STRING_TOKEN(STRING_HELP),
+ flags = INTERACTIVE,
+ minsize = 5,
+ maxsize = 10,
+ default = STRING_TOKEN(STRING_DEFAULT), defaultstore = StandardDefault,
+ default = STRING_TOKEN(STRING_PROMPT), defaultstore = ManufactureDefault,
+ endstring;
+
+ date
+ varid = FormData.DateValue,
+ prompt = STRING_TOKEN(DATE_PROMPT),
+ help = STRING_TOKEN(DATE_HELP),
+ default = 2021/05/22,
+ enddate;
+
+ time
+ varid = FormData.TimeValue,
+ prompt = STRING_TOKEN(TIME_PROMPT),
+ help = STRING_TOKEN(TIME_HELP),
+ default = 23:55:33,
+ endtime;
+
+ oneof
+ name = OneOfQuestion,
+ varid = FormData.OneOfValue,
+ prompt = STRING_TOKEN(ONEOF_PROMPT),
+ help = STRING_TOKEN(ONEOF_HELP),
+ option text = STRING_TOKEN(ONEOF_OPTION1), value = 0x00, flags = 0;
+ option text = STRING_TOKEN(ONEOF_OPTION2), value = 0x33, flags = MANUFACTURING;
+ option text = STRING_TOKEN(ONEOF_OPTION3), value = 0x55, flags = DEFAULT;
+ 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;
+ default = {0x0c, 0x0b, 0x0a},
+ endlist;
+
+ resetbutton
+ defaultstore = StandardDefault,
+ prompt = STRING_TOKEN(BTN_STANDARD_DEFAULT_PROMPT),
+ help = STRING_TOKEN(BTN_STANDARD_DEFAULT_HELP),
+ endresetbutton;
+
+ resetbutton
+ defaultstore = ManufactureDefault,
+ prompt = STRING_TOKEN(BTN_MFG_DEFAULT_PROMPT),
+ help = STRING_TOKEN(BTN_MFG_DEFAULT_HELP),
+ endresetbutton;
+ endform;
+endformset;
diff --git a/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/HIIFormDataElementsVarstore.c b/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/HIIFormDataElementsVarstore.c
new file mode 100644
index 0000000..42af437
--- /dev/null
+++ b/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/HIIFormDataElementsVarstore.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2022, Konstantin Aladyshev <aladyshev22@gmail.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#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 <Library/UefiHiiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Protocol/HiiConfigAccess.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)
+ }
+ },
+ DATAPATH_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_HII_CONFIG_ACCESS_PROTOCOL mConfigAccess;
+EFI_GUID StorageGuid = STORAGE_GUID;
+EFI_STRING StorageName = L"FormData";
+
+VARIABLE_STRUCTURE FormStorage;
+
+
+STATIC
+EFI_STATUS
+EFIAPI
+ExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+)
+{
+ DEBUG ((EFI_D_INFO, "ExtractConfig: Request=%s\n", Request));
+
+ BOOLEAN AllocatedRequest = FALSE;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Request != NULL) && !HiiIsConfigHdrMatch(Request, &StorageGuid, StorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ EFI_STRING ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ EFI_STRING ConfigRequestHdr = HiiConstructConfigHdr(&StorageGuid, StorageName, mDriverHandle);
+ UINTN Size = (StrLen(ConfigRequestHdr) + StrLen(L"&OFFSET=0&WIDTH=") + sizeof(UINTN)*2 + 1) * sizeof(CHAR16);
+ ConfigRequest = AllocateZeroPool(Size);
+ AllocatedRequest = TRUE;
+ UnicodeSPrint(ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, sizeof(VARIABLE_STRUCTURE));
+ FreePool(ConfigRequestHdr);
+ }
+ EFI_STATUS Status = gHiiConfigRouting->BlockToConfig(gHiiConfigRouting,
+ ConfigRequest,
+ (UINT8*)&FormStorage,
+ sizeof(VARIABLE_STRUCTURE),
+ Results,
+ Progress);
+
+ if (AllocatedRequest) {
+ FreePool(ConfigRequest);
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr(Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen(Request);
+ }
+ }
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+RouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+)
+{
+ DEBUG ((EFI_D_INFO, "RouteConfig: Configuration=%s\n", Configuration));
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UINTN BlockSize = sizeof(VARIABLE_STRUCTURE);
+ EFI_STATUS Status = gHiiConfigRouting->ConfigToBlock(gHiiConfigRouting,
+ Configuration,
+ (UINT8*)&FormStorage,
+ &BlockSize,
+ Progress);
+
+ return Status;
+}
+
+EFI_STRING ActionToStr(EFI_BROWSER_ACTION Action)
+{
+ switch (Action) {
+ case EFI_BROWSER_ACTION_CHANGING:
+ return L"EFI_BROWSER_ACTION_CHANGING";
+ case EFI_BROWSER_ACTION_CHANGED:
+ return L"EFI_BROWSER_ACTION_CHANGED";
+ case EFI_BROWSER_ACTION_RETRIEVE:
+ return L"EFI_BROWSER_ACTION_RETRIEVE";
+ case EFI_BROWSER_ACTION_FORM_OPEN:
+ return L"EFI_BROWSER_ACTION_FORM_OPEN";
+ case EFI_BROWSER_ACTION_FORM_CLOSE:
+ return L"EFI_BROWSER_ACTION_FORM_CLOSE";
+ case EFI_BROWSER_ACTION_SUBMITTED:
+ return L"EFI_BROWSER_ACTION_SUBMITTED";
+ case EFI_BROWSER_ACTION_DEFAULT_STANDARD:
+ return L"EFI_BROWSER_ACTION_DEFAULT_STANDARD";
+ case EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING:
+ return L"EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING";
+ case EFI_BROWSER_ACTION_DEFAULT_SAFE:
+ return L"EFI_BROWSER_ACTION_DEFAULT_SAFE";
+ case EFI_BROWSER_ACTION_DEFAULT_PLATFORM:
+ return L"EFI_BROWSER_ACTION_DEFAULT_PLATFORM";
+ case EFI_BROWSER_ACTION_DEFAULT_HARDWARE:
+ return L"EFI_BROWSER_ACTION_DEFAULT_HARDWARE";
+ case EFI_BROWSER_ACTION_DEFAULT_FIRMWARE:
+ return L"EFI_BROWSER_ACTION_DEFAULT_FIRMWARE";
+ default:
+ return L"Unknown";
+ }
+}
+
+EFI_STRING TypeToStr(UINT8 Type)
+{
+ switch (Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ return L"EFI_IFR_TYPE_NUM_SIZE_8";
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ return L"EFI_IFR_TYPE_NUM_SIZE_16";
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ return L"EFI_IFR_TYPE_NUM_SIZE_32";
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ return L"EFI_IFR_TYPE_NUM_SIZE_64";
+ case EFI_IFR_TYPE_BOOLEAN:
+ return L"EFI_IFR_TYPE_BOOLEAN";
+ case EFI_IFR_TYPE_TIME:
+ return L"EFI_IFR_TYPE_TIME";
+ case EFI_IFR_TYPE_DATE:
+ return L"EFI_IFR_TYPE_DATE";
+ case EFI_IFR_TYPE_STRING:
+ return L"EFI_IFR_TYPE_STRING";
+ case EFI_IFR_TYPE_OTHER:
+ return L"EFI_IFR_TYPE_OTHER";
+ case EFI_IFR_TYPE_UNDEFINED:
+ return L"EFI_IFR_TYPE_UNDEFINED";
+ case EFI_IFR_TYPE_ACTION:
+ return L"EFI_IFR_TYPE_ACTION";
+ case EFI_IFR_TYPE_BUFFER:
+ return L"EFI_IFR_TYPE_BUFFER";
+ case EFI_IFR_TYPE_REF:
+ return L"EFI_IFR_TYPE_REF";
+ default:
+ return L"Unknown";
+ }
+}
+
+VOID DebugCallbackValue(UINT8 Type, EFI_IFR_TYPE_VALUE *Value)
+{
+ switch (Type) {
+ case EFI_IFR_TYPE_NUM_SIZE_8:
+ DEBUG ((EFI_D_INFO, "%d\n", Value->u8));
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_16:
+ DEBUG ((EFI_D_INFO, "%d\n", Value->u16));
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_32:
+ DEBUG ((EFI_D_INFO, "%d\n", Value->u32));
+ break;
+ case EFI_IFR_TYPE_NUM_SIZE_64:
+ DEBUG ((EFI_D_INFO, "%ld\n", Value->u64));
+ break;
+ case EFI_IFR_TYPE_BOOLEAN:
+ DEBUG ((EFI_D_INFO, "%d\n", Value->b));
+ break;
+ case EFI_IFR_TYPE_TIME:
+ DEBUG ((EFI_D_INFO, "%02d:%02d:%02d\n", Value->time.Hour, Value->time.Minute, Value->time.Second));
+ break;
+ case EFI_IFR_TYPE_DATE:
+ DEBUG ((EFI_D_INFO, "%04d/%02d/%02d\n", Value->date.Year, Value->date.Month, Value->date.Day));
+ break;
+ case EFI_IFR_TYPE_STRING:
+ DEBUG ((EFI_D_INFO, "%s\n", HiiGetString(mHiiHandle, Value->string, "en-US") ));
+ break;
+ default:
+ DEBUG ((EFI_D_INFO, "Unknown\n" ));
+ break;
+ }
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+Callback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN OUT EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ DEBUG ((EFI_D_INFO, "Callback: Action=%s, QuestionId=0x%04x, Type=%s, Value=", ActionToStr(Action), QuestionId, TypeToStr(Type)));
+ DebugCallbackValue(Type, Value);
+
+ return EFI_UNSUPPORTED;
+}
+
+
+EFI_STATUS
+EFIAPI
+HIIFormDataElementsVarstoreUnload (
+ EFI_HANDLE ImageHandle
+ )
+{
+ if (mHiiHandle != NULL)
+ HiiRemovePackages(mHiiHandle);
+
+ EFI_STATUS Status = gBS->UninstallMultipleProtocolInterfaces(
+ mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mConfigAccess,
+ NULL);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+HIIFormDataElementsVarstoreEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ mConfigAccess.ExtractConfig = &ExtractConfig;
+ mConfigAccess.RouteConfig = &RouteConfig;
+ mConfigAccess.Callback = &Callback;
+
+ EFI_STATUS Status;
+ Status = gBS->InstallMultipleProtocolInterfaces(
+ &mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ mHiiHandle = HiiAddPackages(
+ &gEfiCallerIdGuid,
+ mDriverHandle,
+ HIIFormDataElementsVarstoreStrings,
+ FormBin,
+ NULL
+ );
+ if (mHiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces(
+ mDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mConfigAccess,
+ NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EFI_STRING ConfigStr = HiiConstructConfigHdr(&StorageGuid, StorageName, mDriverHandle);
+ UINT16 DefaultId = 1;
+ if (!HiiSetToDefaults(ConfigStr, DefaultId)) {
+ Print(L"Error! Can't set default configuration #%d\n", DefaultId);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/HIIFormDataElementsVarstore.inf b/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/HIIFormDataElementsVarstore.inf
new file mode 100644
index 0000000..db69f16
--- /dev/null
+++ b/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/HIIFormDataElementsVarstore.inf
@@ -0,0 +1,34 @@
+##
+# Copyright (c) 2022, Konstantin Aladyshev <aladyshev22@gmail.com>
+#
+# SPDX-License-Identifier: MIT
+##
+
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = HIIFormDataElementsVarstore
+ FILE_GUID = 162201c9-1208-4567-bab6-e9d32ae90e84
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = HIIFormDataElementsVarstoreEntryPoint
+ UNLOAD_IMAGE = HIIFormDataElementsVarstoreUnload
+
+[Sources]
+ HIIFormDataElementsVarstore.c
+ Strings.uni
+ Form.vfr
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiLib
+ HiiLib
+ DebugLib
+ UefiHiiServicesLib
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid
+
diff --git a/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Strings.uni b/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Strings.uni
new file mode 100644
index 0000000..10a410e
--- /dev/null
+++ b/Lessons_uncategorized/Lesson_Varstore_5/UefiLessonsPkg/HIIFormDataElementsVarstore/Strings.uni
@@ -0,0 +1,46 @@
+//
+// Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com>
+//
+// SPDX-License-Identifier: MIT
+//
+
+#langdef en-US "English"
+#langdef x-UEFI-OEM "OEM_NameSpace"
+
+#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"
+ #language x-UEFI-OEM "CheckboxKey"
+#string CHECKBOX_HELP #language en-US "Checkbox help"
+#string NUMERIC_PROMPT #language en-US "Numeric prompt"
+ #language x-UEFI-OEM "NumericKey"
+#string NUMERIC_HELP #language en-US "Numeric help"
+#string STRING_PROMPT #language en-US "String prompt"
+ #language x-UEFI-OEM "StringKey"
+#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"
+#string WARNING_IF_PROMPT #language en-US "WarningIf prompt"
+#string NOSUBMIT_IF_PROMPT #language en-US "NoSubmitIf prompt"
+#string INCONSISTENT_IF_PROMPT #language en-US "InconsistentIf prompt"
+#string TEST_STRING #language en-US "EDKII"
+#string STRING_DEFAULT #language en-US "String default"
+#string STANDARD_DEFAULT_PROMPT #language en-US "Standard default"
+#string MFG_DEFAULT_PROMPT #language en-US "Manufacture default"
+#string BTN_STANDARD_DEFAULT_PROMPT #language en-US "Reset to standard default prompt"
+#string BTN_STANDARD_DEFAULT_HELP #language en-US "Reset to standard default help"
+#string BTN_MFG_DEFAULT_PROMPT #language en-US "Reset to manufacture default prompt"
+#string BTN_MFG_DEFAULT_HELP #language en-US "Reset to manufacture default help"
diff --git a/README.md b/README.md
index 7787637..606aecc 100644
--- a/README.md
+++ b/README.md
@@ -90,6 +90,7 @@ _____
- [Lesson XX](Lessons_uncategorized/Lesson_Varstore_2): Create a driver with `Buffer Storage` - Part 2: Investigate when and how `ExtractConfig`/`RouteConfig`/`Callback` functions are called
- [Lesson XX](Lessons_uncategorized/Lesson_Varstore_3): Create a driver with `Buffer Storage` - Part 3: Use `BlockToConfig()`/`ConfigToBlock()` functions to handle configuration requests
- [Lesson XX](Lessons_uncategorized/Lesson_Varstore_4): Create a driver with `Buffer Storage` - Part 4: Make `ExtractConfig()` function compatible with UEFI specification
+- [Lesson XX](Lessons_uncategorized/Lesson_Varstore_5): Investigate when and how the Form Browser calls `EFI_HII_CONFIG_ROUTING_PROTOCOL.Callback()` function
_____
- [Lesson XX](Lessons_uncategorized/Lesson_ARCH): Architecture specifier in section names
- [Lesson XX](Lessons_uncategorized/Lesson_SKU): SKU specifier in section names