diff options
author | Konstantin Aladyshev <aladyshev22@gmail.com> | 2024-02-21 18:58:35 +0300 |
---|---|---|
committer | Konstantin Aladyshev <aladyshev22@gmail.com> | 2024-02-21 18:58:35 +0300 |
commit | dcd9aa0c3d8f764c0ba3d3348451b8d7773971eb (patch) | |
tree | 10b3562a79f6e04af9f167b8bc99ccf3b01e1fe4 | |
parent | 8540c30aa69a939327b8a1c2cca7a85ed83cace4 (diff) | |
download | UEFI-Lessons-dcd9aa0c3d8f764c0ba3d3348451b8d7773971eb.tar.gz UEFI-Lessons-dcd9aa0c3d8f764c0ba3d3348451b8d7773971eb.tar.bz2 UEFI-Lessons-dcd9aa0c3d8f764c0ba3d3348451b8d7773971eb.zip |
Add lesson about the form browser action requests
Signed-off-by: Konstantin Aladyshev <aladyshev22@gmail.com>
-rw-r--r-- | Lessons_uncategorized/Lesson_Varstore_7/README.md | 212 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | UefiLessonsPkg/HIIFormCallbackDebug2/Data.h | 23 | ||||
-rw-r--r-- | UefiLessonsPkg/HIIFormCallbackDebug2/Form.vfr | 130 | ||||
-rw-r--r-- | UefiLessonsPkg/HIIFormCallbackDebug2/HIIFormCallbackDebug2.c | 444 | ||||
-rw-r--r-- | UefiLessonsPkg/HIIFormCallbackDebug2/HIIFormCallbackDebug2.inf | 34 | ||||
-rw-r--r-- | UefiLessonsPkg/HIIFormCallbackDebug2/Strings.uni | 54 | ||||
-rw-r--r-- | UefiLessonsPkg/UefiLessonsPkg.dsc | 1 | ||||
-rw-r--r-- | bin/HIIFormCallbackDebug2.efi | bin | 0 -> 30784 bytes |
9 files changed, 899 insertions, 0 deletions
diff --git a/Lessons_uncategorized/Lesson_Varstore_7/README.md b/Lessons_uncategorized/Lesson_Varstore_7/README.md new file mode 100644 index 0000000..80f1ed5 --- /dev/null +++ b/Lessons_uncategorized/Lesson_Varstore_7/README.md @@ -0,0 +1,212 @@ +Let's continue our investigation of the `EFI_HII_CONFIG_ACCESS_PROTOCOL.Callback` function. + +In the last lesson we've researched all the input parameters of the function and understood when the function is called. + +Now let's check the output parameter of the function - `OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest`. According to the UEFI specification `Upon return, the callback function may specify the desired browser action`. + +All the available values for the `ActionRequest` are listed in the file [https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/FormBrowser2.h](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/FormBrowser2.h): +``` +typedef UINTN EFI_BROWSER_ACTION_REQUEST; + +#define EFI_BROWSER_ACTION_REQUEST_NONE 0 +#define EFI_BROWSER_ACTION_REQUEST_RESET 1 +#define EFI_BROWSER_ACTION_REQUEST_SUBMIT 2 +#define EFI_BROWSER_ACTION_REQUEST_EXIT 3 +#define EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT 4 +#define EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT 5 +#define EFI_BROWSER_ACTION_REQUEST_FORM_APPLY 6 +#define EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD 7 +#define EFI_BROWSER_ACTION_REQUEST_RECONNECT 8 +#define EFI_BROWSER_ACTION_REQUEST_QUESTION_APPLY 9 +``` + +According to the UEFI specification: +``` +If the callback function returns with the ActionRequest set to: + _NONE, then the Forms Browser will take no special behavior, + _RESET, then the Forms Browser will exit and request the platform to reset, + _SUBMIT, then the Forms Browser will save all modified question values to storage and exit, + _EXIT, then the Forms Browser will discard all modified question values and exit, + _FORM_SUBMIT_EXIT, then the Forms Browser will write all modified question values on the selected form to storage and then exit the selected form, + _FORM_DISCARD_EXIT, then the Forms Browser will discard the modified question values on the selected form and then exit the selected form, + _FORM_APPLY, then the Forms Browser will write all modified current question values on the selected form to storage, + _FORM_DISCARD, then the Forms Browser will discard the current question values on the selected form and replace them with the original question values, + _RECONNECT, a hardware and/or software configuration change was performed by the user, and the controller needs to be reconnected for the driver to recognize the change. The Forms Browser is required to call the EFI Boot Service DisconnectController() followed by the EFI Boot Service ConnectController() to reconnect the controller, and then exit. The controller handle passed to DisconnectController() and ConnectController() is the handle on which this EFI_HII_CONFIG_ACCESS_PROTOCOL is installed, + _QUESTION_APPLY, then the Forms Browser will write the current modified question value on the selected form to storage. +``` + +In a short form this means: +``` +_NONE - nothing +_RESET - exit and reset platform +_SUBMIT - save all modifications and exit +_EXIT - discard all modifications and exit +_FORM_SUBMIT_EXIT - save current form modifications and exit form +_FORM_DISCARD_EXIT - discard current form modifications and exit form +_FORM_APPLY - save current form modifications +_FORM_DISCARD - discard current form modifications +_RECONNECT - reconnect the controller and exit +_QUESTION_APPLY - save current question modification +``` + +Let's try to see them in action. For that we would create `HIIFormCallbackDebug2` based on our recent `HIIFormCallbackDebug` driver. + +Since the actual `ActionRequest` values are numbers between 0 and 9 we can test them via our `numeric` input. You already know that when the user changes the element value in the Form Browser, the following callbacks are called: +- `EFI_BROWSER_ACTION_CHANGING` +- `EFI_BROWSER_ACTION_CHANGED` + +So let's set the `*ActionRequest` based on the user input in the `EFI_BROWSER_ACTION_CHANGED` callback for the `numeric`: +```cpp +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); + + HIIPopupCallbackInfo(Action, QuestionId, Type, Value); + + if ((QuestionId == NUMERIC_QUESTION_ID) && (Action == EFI_BROWSER_ACTION_CHANGED)) { + if ((Value->u16 >= 0) && (Value->u16 <= 9)) { + *ActionRequest = Value->u16; + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; +} +``` +This way when you set `numeric` to 4 for example, in the `EFI_BROWSER_ACTION_CHANGED` callback you would return `ActionRequest = 4 = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT`. Neat! + +As you can see from the UEFI specification for the `ActionRequest` some actions close form, and some close entire formset. So to fully debug it we need to create a multiform formset. + +Let's create 3 forms linked in the following way: +``` +Form1 -> Form2 -> Form3 +``` +And move one of our interactive elements (for example `string`) to the Form2 and the rest of the input element leave in the most nested Form3. + +Here is a snippet how it would look in the VFR: +``` +formset + + <...> + + form + formid = 1, + title = STRING_TOKEN(FORMID1_TITLE); + + goto 2, + prompt = STRING_TOKEN(GOTO_FORM2_PROMPT), + help = STRING_TOKEN(GOTO_FORM2_HELP); + + endform; + + form + formid = 2, + title = STRING_TOKEN(FORMID2_TITLE); + + goto 3, + prompt = STRING_TOKEN(GOTO_FORM3_PROMPT), + help = STRING_TOKEN(GOTO_FORM3_HELP); + + string + <...> + endstring; + + endform; + + form + formid = 3, + title = STRING_TOKEN(FORMID3_TITLE); + + <... all other elements ... > + + endform; +endformset; +``` + +Off course don't forget to define the newly added strings: +``` +#string FORMID1_TITLE #language en-US "Form 1" +#string FORMID2_TITLE #language en-US "Form 2" +#string FORMID3_TITLE #language en-US "Form 3" +#string GOTO_FORM2_PROMPT #language en-US "Enter Form 2" +#string GOTO_FORM2_HELP #language en-US "Enter Form 2" +#string GOTO_FORM3_PROMPT #language en-US "Enter Form 3" +#string GOTO_FORM3_HELP #language en-US "Enter Form 3" +``` + +Now you can experiment with the driver, by setting different values to the `numeric`. + +First of all couple of new facts that we can obtain from the multiform formset: +- `Extract` is called once for all the elements when you enter the first form of the formset (Form1), +- Callbacks `FORM_OPEN`/`FORM_RETRIEVE`/`FORM_CLOSE` are called when you enter the from with the target element. I.e for `string` it will be Form2, for the rest of elements - Form3, +- You can leave the form with a changed value, but not a formset. When you try to leave formset the browser will ask you if you want to submit the changes, +- Even if the elements are on different forms the submit action (F10) would produce the callbacks for all the elements + +Now back to the `ActionRequest` investigation. Here I've tried to describe addition actions that you would get from setting the `ActionRequest` (i.e. our `numeric`) to the particular value. +``` +Changing to 0 - _NONE - no additional actions + +Changing to 1 - _RESET + + ACTION_CHANGED <--- revert uncommited changes for all elements in the formset + + ACTION_FORM_CLOSE <--- close for all elements on the form + + Close entire formset + (Now if you try to exit browser it will prompt that the platform reset is needed) + +Changing to 2 - _SUBMIT + + Route with settings for all elements + + ACTION_SUBMITTED <--- submit for all elements in the formset + + ACTION_FORM_CLOSE <--- close for all elements on the form + + Close entire formset + +Changing to 3 - _EXIT + + ACTION_CHANGED <--- revert uncommited changes for all elements in the formset + + ACTION_FORM_CLOSE <--- close for all elements on the form + + Close entire formset + +Changing to 4 - _FORM_SUBMIT_EXIT + + Route with settings for all elements + + ACTION_SUBMITTED <--- submit for all elements on the form + + ACTION_FORM_CLOSE <--- close for all elements on the form + + Close current form + +Changing to 5 - _FORM_DISCARD_EXIT + + ACTION_CHANGED <--- revert uncommited changes for all elements on the form + + ACTION_FORM_CLOSE <--- close for all elements on the form + + Close current form + +Changing to 6 - _FORM_APPLY + + Route with settings for all elements + + ACTION_SUBMITTED <--- submit for all form elements + +Changing to 7 - _FORM_DISCARD + + ACTION_CHANGED <--- revert uncommited changes for all form elements + +Changing to 8 - _RECONNECT + "Reconnect is required, confirm the changes then exit and reconnect" + If user answers "N" + + ACTION_CHANGED <--- revert uncommited changes in thr formset + + ACTION_FORM_CLOSE <--- close for all elements in the form + + Close entire formset + If user answers "Y" + + Route with settings for all elements + + ACTION_SUBMITTED <--- submit for all elements in a formset + + ACTION_FORM_CLOSE <--- close for all elements in the form + + Reconnect + + Close entire formset + +Changing to 9 - _QUESTION_APPLY <--- no additional callbacks + + Route with settings for target question only +``` + +I hope I didn't mess anything in the above description. Anyway now you have a `HIIFormCallbackDebug2` application to verify how the FormBrowser calls callbacks for the elements. @@ -93,6 +93,7 @@ _____ - [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_Varstore_6): Popup windows in edk2. Creating popups with the `EFI_HII_POPUP_PROTOCOL.CreatePopup()` and `CreatePopUp` functions +- [Lesson XX](Lessons_uncategorized/Lesson_Varstore_7): Action requests for the Form Browser from the `EFI_HII_CONFIG_ROUTING_PROTOCOL.Callback()` function - [Lesson XX](Lessons_uncategorized/Lesson_Password): The `password` VFR input element - Part 1: Basic `Callback()` implementation to handle password element - [Lesson XX](Lessons_uncategorized/Lesson_Password_2): The `password` VFR input element - Part 2: Use `EFI_HASH2_PROTOCOL` to calculate password string hash _____ diff --git a/UefiLessonsPkg/HIIFormCallbackDebug2/Data.h b/UefiLessonsPkg/HIIFormCallbackDebug2/Data.h new file mode 100644 index 0000000..8df01aa --- /dev/null +++ b/UefiLessonsPkg/HIIFormCallbackDebug2/Data.h @@ -0,0 +1,23 @@ +#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}} + +#define CHECKBOX_QUESTION_ID 0x5555 +#define NUMERIC_QUESTION_ID 0x4444 + +#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/UefiLessonsPkg/HIIFormCallbackDebug2/Form.vfr b/UefiLessonsPkg/HIIFormCallbackDebug2/Form.vfr new file mode 100644 index 0000000..b138472 --- /dev/null +++ b/UefiLessonsPkg/HIIFormCallbackDebug2/Form.vfr @@ -0,0 +1,130 @@ +#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); + + goto 2, + prompt = STRING_TOKEN(GOTO_FORM2_PROMPT), + help = STRING_TOKEN(GOTO_FORM2_HELP); + + endform; + + form + formid = 2, + title = STRING_TOKEN(FORMID2_TITLE); + + goto 3, + prompt = STRING_TOKEN(GOTO_FORM3_PROMPT), + help = STRING_TOKEN(GOTO_FORM3_HELP); + + 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; + + endform; + + form + formid = 3, + title = STRING_TOKEN(FORMID3_TITLE); + + checkbox + varid = FormData.CheckboxValue, + questionid = CHECKBOX_QUESTION_ID, + 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 = NUMERIC_QUESTION_ID, + prompt = STRING_TOKEN(NUMERIC_PROMPT), + help = STRING_TOKEN(NUMERIC_HELP), + flags = NUMERIC_SIZE_2 | DISPLAY_UINT_HEX | INTERACTIVE, + //minimum = 0x1234, + //maximum = 0xaa55, + minimum = 0, + maximum = 10, + step = 1, + default = 7, defaultstore = StandardDefault, + default = 8, defaultstore = ManufactureDefault, + endnumeric; + + + 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/UefiLessonsPkg/HIIFormCallbackDebug2/HIIFormCallbackDebug2.c b/UefiLessonsPkg/HIIFormCallbackDebug2/HIIFormCallbackDebug2.c new file mode 100644 index 0000000..f70718a --- /dev/null +++ b/UefiLessonsPkg/HIIFormCallbackDebug2/HIIFormCallbackDebug2.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2024, 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 <Protocol/HiiPopup.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 +) +{ + EFI_INPUT_KEY Key; + do { + CreatePopUp(EFI_TEXT_ATTR(EFI_RED, EFI_BLACK), &Key, L"Extract: ", Request, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + 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 +) +{ + EFI_INPUT_KEY Key; + do { + CreatePopUp(EFI_TEXT_ATTR(EFI_RED, EFI_BLACK), &Key, L"Route: ", Configuration, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + 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 CallbackValueToStr(UINT8 Type, EFI_IFR_TYPE_VALUE *Value, EFI_STRING* ValueStr, UINTN ValueStrSize) +{ + switch (Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + UnicodeSPrint(*ValueStr, ValueStrSize, L"%d", Value->u8); + break; + case EFI_IFR_TYPE_NUM_SIZE_16: + UnicodeSPrint(*ValueStr, ValueStrSize, L"%d", Value->u16); + break; + case EFI_IFR_TYPE_NUM_SIZE_32: + UnicodeSPrint(*ValueStr, ValueStrSize, L"%d", Value->u32); + break; + case EFI_IFR_TYPE_NUM_SIZE_64: + UnicodeSPrint(*ValueStr, ValueStrSize, L"%ld", Value->u64); + break; + case EFI_IFR_TYPE_BOOLEAN: + UnicodeSPrint(*ValueStr, ValueStrSize, L"%d", Value->b); + break; + case EFI_IFR_TYPE_TIME: + UnicodeSPrint(*ValueStr, ValueStrSize, L"%02d:%02d:%02d", Value->time.Hour, Value->time.Minute, Value->time.Second); + break; + case EFI_IFR_TYPE_DATE: + UnicodeSPrint(*ValueStr, ValueStrSize, L"%04d/%02d/%02d", Value->date.Year, Value->date.Month, Value->date.Day); + break; + case EFI_IFR_TYPE_STRING: + if (Value->string) + UnicodeSPrint(*ValueStr, ValueStrSize, L"%s", HiiGetString(mHiiHandle, Value->string, "en-US")); + else + UnicodeSPrint(*ValueStr, ValueStrSize, L"NO STRING!"); + break; + default: + UnicodeSPrint(*ValueStr, ValueStrSize, L"Unknown"); + break; + } +} + +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: + if (Value->string) + DEBUG ((EFI_D_INFO, "%s\n", HiiGetString(mHiiHandle, Value->string, "en-US") )); + else + DEBUG ((EFI_D_INFO, "NO STRING!\n" )); + break; + default: + DEBUG ((EFI_D_INFO, "Unknown\n" )); + break; + } +} + +VOID HIIPopupCallbackInfo(EFI_BROWSER_ACTION Action, EFI_QUESTION_ID QuestionId, UINT8 Type, EFI_IFR_TYPE_VALUE* Value) +{ + EFI_STATUS Status; + EFI_HII_POPUP_PROTOCOL* HiiPopup; + EFI_HII_POPUP_SELECTION UserSelection; + Status = gBS->LocateProtocol(&gEfiHiiPopupProtocolGuid, + NULL, + (VOID **)&HiiPopup); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "Error! Can't find EFI_HII_POPUP_PROTOCOL\n")); + return; + } + + UINTN Size = 300; + EFI_STRING ValueStr = AllocateZeroPool(Size); + CallbackValueToStr(Type, Value, &ValueStr, Size); + EFI_STRING PopupStr = AllocateZeroPool(Size); + UnicodeSPrint(PopupStr, Size, L"Callback:\nAction=%s\nQuestionId=0x%04x\nType=%s\nValue=%s", ActionToStr(Action), QuestionId, TypeToStr(Type), ValueStr); + FreePool(ValueStr); + HiiSetString(mHiiHandle, STRING_TOKEN(POPUP_MESSAGE), PopupStr, NULL); + Status = HiiPopup->CreatePopup(HiiPopup, + EfiHiiPopupStyleInfo, + EfiHiiPopupTypeOk, + mHiiHandle, + STRING_TOKEN(POPUP_MESSAGE), + &UserSelection + ); + FreePool(PopupStr); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "Error! Can't create popup, %r\n", Status)); + return; + } +} + +VOID PopupCallbackInfo(EFI_BROWSER_ACTION Action, EFI_QUESTION_ID QuestionId, UINT8 Type, EFI_IFR_TYPE_VALUE* Value) +{ + EFI_INPUT_KEY Key; + + UINTN Size = 100; + EFI_STRING ActionStr = AllocateZeroPool(Size); + EFI_STRING QuestionIdStr = AllocateZeroPool(Size); + EFI_STRING TypeStr = AllocateZeroPool(Size); + EFI_STRING ValueStr = AllocateZeroPool(Size); + EFI_STRING ValStr = AllocateZeroPool(Size); + CallbackValueToStr(Type, Value, &ValStr, Size); + UnicodeSPrint(ActionStr, Size, L"Action=%s", ActionToStr(Action)); + UnicodeSPrint(QuestionIdStr, Size, L"QuestionId=0x%04x", QuestionId); + UnicodeSPrint(TypeStr, Size, L"Type=%s", TypeToStr(Type)); + UnicodeSPrint(ValueStr, Size, L"Value=%s", ValStr); + do { + //CreatePopUp(EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_BLUE), &Key, L"Callback:", ActionStr, QuestionIdStr, TypeStr, ValueStr, NULL); + CreatePopUp(EFI_TEXT_ATTR(EFI_RED, EFI_BLACK), &Key, L"Callback:", ActionStr, QuestionIdStr, TypeStr, ValueStr, NULL); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + FreePool(ActionStr); + FreePool(QuestionIdStr); + FreePool(TypeStr); + FreePool(ValueStr); + FreePool(ValStr); +} + +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); + + HIIPopupCallbackInfo(Action, QuestionId, Type, Value); + //PopupCallbackInfo(Action, QuestionId, Type, Value); + + if ((QuestionId == NUMERIC_QUESTION_ID) && (Action == EFI_BROWSER_ACTION_CHANGED)) { + if ((Value->u16 >= 0) && (Value->u16 <= 9)) { + *ActionRequest = Value->u16; + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; +} + + +EFI_STATUS +EFIAPI +HIIFormCallbackDebug2Unload ( + EFI_HANDLE ImageHandle + ) +{ + if (mHiiHandle != NULL) + HiiRemovePackages(mHiiHandle); + + EFI_STATUS Status = gBS->UninstallMultipleProtocolInterfaces( + mDriverHandle, + &gEfiDevicePathProtocolGuid, + &mHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &mConfigAccess, + NULL); + + return Status; +} + +EFI_STATUS +EFIAPI +HIIFormCallbackDebug2EntryPoint ( + 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, + HIIFormCallbackDebug2Strings, + 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/UefiLessonsPkg/HIIFormCallbackDebug2/HIIFormCallbackDebug2.inf b/UefiLessonsPkg/HIIFormCallbackDebug2/HIIFormCallbackDebug2.inf new file mode 100644 index 0000000..1b363d5 --- /dev/null +++ b/UefiLessonsPkg/HIIFormCallbackDebug2/HIIFormCallbackDebug2.inf @@ -0,0 +1,34 @@ +## +# Copyright (c) 2024, Konstantin Aladyshev <aladyshev22@gmail.com> +# +# SPDX-License-Identifier: MIT +## + +[Defines] + INF_VERSION = 1.25 + BASE_NAME = HIIFormCallbackDebug2 + FILE_GUID = 67ca8db1-ff6e-4d3f-b503-113791c9008d + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = HIIFormCallbackDebug2EntryPoint + UNLOAD_IMAGE = HIIFormCallbackDebug2Unload + +[Sources] + HIIFormCallbackDebug2.c + Strings.uni + Form.vfr + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiLib + HiiLib + DebugLib + UefiHiiServicesLib + +[Protocols] + gEfiHiiConfigAccessProtocolGuid + gEfiHiiPopupProtocolGuid diff --git a/UefiLessonsPkg/HIIFormCallbackDebug2/Strings.uni b/UefiLessonsPkg/HIIFormCallbackDebug2/Strings.uni new file mode 100644 index 0000000..9b2142d --- /dev/null +++ b/UefiLessonsPkg/HIIFormCallbackDebug2/Strings.uni @@ -0,0 +1,54 @@ +// +// 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 "Form 1" +#string FORMID2_TITLE #language en-US "Form 2" +#string FORMID3_TITLE #language en-US "Form 3" +#string GOTO_FORM2_PROMPT #language en-US "Enter Form 2" +#string GOTO_FORM2_HELP #language en-US "Enter Form 2" +#string GOTO_FORM3_PROMPT #language en-US "Enter Form 3" +#string GOTO_FORM3_HELP #language en-US "Enter Form 3" + +#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" +#string POPUP_MESSAGE #language en-US "Popup message" diff --git a/UefiLessonsPkg/UefiLessonsPkg.dsc b/UefiLessonsPkg/UefiLessonsPkg.dsc index 0722ca7..c5698ca 100644 --- a/UefiLessonsPkg/UefiLessonsPkg.dsc +++ b/UefiLessonsPkg/UefiLessonsPkg.dsc @@ -98,6 +98,7 @@ UefiLessonsPkg/PasswordForm/PasswordForm.inf UefiLessonsPkg/PasswordFormWithHash/PasswordFormWithHash.inf UefiLessonsPkg/HIIFormCallbackDebug/HIIFormCallbackDebug.inf + UefiLessonsPkg/HIIFormCallbackDebug2/HIIFormCallbackDebug2.inf #[PcdsFixedAtBuild] # gUefiLessonsPkgTokenSpaceGuid.PcdInt8|0x88|UINT8|0x3B81CDF1 diff --git a/bin/HIIFormCallbackDebug2.efi b/bin/HIIFormCallbackDebug2.efi Binary files differnew file mode 100644 index 0000000..d6f35c9 --- /dev/null +++ b/bin/HIIFormCallbackDebug2.efi |