diff options
author | Konstantin Aladyshev <aladyshev22@gmail.com> | 2021-12-30 16:21:10 +0300 |
---|---|---|
committer | Konstantin Aladyshev <aladyshev22@gmail.com> | 2021-12-30 16:22:24 +0300 |
commit | 03fd5898331a52003250ca2e21bbd5f1452a1dbd (patch) | |
tree | d3e2aa5a34404b0d9908e6b1bd4683e6f5568196 /Lessons | |
parent | df6a98ab804500e843b08307c20d8f890f148021 (diff) | |
download | UEFI-Lessons-03fd5898331a52003250ca2e21bbd5f1452a1dbd.tar.gz UEFI-Lessons-03fd5898331a52003250ca2e21bbd5f1452a1dbd.tar.bz2 UEFI-Lessons-03fd5898331a52003250ca2e21bbd5f1452a1dbd.zip |
Add draft for lesson 59
Signed-off-by: Konstantin Aladyshev <aladyshev22@gmail.com>
Diffstat (limited to 'Lessons')
7 files changed, 395 insertions, 0 deletions
diff --git a/Lessons/Lesson_59/README.md b/Lessons/Lesson_59/README.md new file mode 100644 index 0000000..1ac4b3c --- /dev/null +++ b/Lessons/Lesson_59/README.md @@ -0,0 +1,102 @@ +Now let's try to actually save some user input with a form. + +For the data we will choose the most simple element - checkbox (https://edk2-docs.gitbook.io/edk-ii-vfr-specification/2_vfr_description_in_bnf/211_vfr_form_definition#2.11.6.5.1-vfr-checkbox-statement-definition) + +Crete new application with a form and insert the following code inside: +``` +checkbox + prompt = STRING_TOKEN(CHECKBOX_TITLE), + help = STRING_TOKEN(CHECKBOX_HELP), +endcheckbox; +``` + +This will give you the following element on form + +![Checkbox1](Checkbox1.png?raw=true "Checkbox1") + +Which you can toggle with a spacebar + +![Checkbox2](Checkbox2.png?raw=true "Checkbox2") + +The checkbox element will produce `EFI_IFR_CHECKBOX` and `EFI_IFR_END` opcodes: +``` + checkbox +>00000039: 06 8E 05 00 06 00 01 00 00 00 FF FF 00 00 + prompt = STRING_TOKEN(0x0005), + help = STRING_TOKEN(0x0006), + endcheckbox; +>00000047: 29 02 +``` + +Here is a definition for the `EFI_IFR_CHECKBOX`: +``` +EFI_IFR_CHECKBOX + +Summary: +Creates a boolean checkbox. + +Prototype: + +#define EFI_IFR_CHECKBOX_OP 0x06 + +typedef struct _EFI_IFR_CHECKBOX { + EFI_IFR_OP_HEADER Header; + EFI_IFR_QUESTION_HEADER Question; + UINT8 Flags; +} EFI_IFR_CHECKBOX; + +Members: +Header The standard question header, where Header.OpCode = EFI_IFR_CHECKBOX_OP. +Question The standard question header. +Flags Flags that describe the behavior of the question. All undefined bits should be zero. + +Description: +Creates a Boolean checkbox question and adds it to the current form. The checkbox has two values: +FALSE if the box is not checked and TRUE if it is. +``` +And for its field `EFI_IFR_QUESTION_HEADER`: +``` +EFI_IFR_QUESTION_HEADER + +Summary: +Standard question header. + +Prototype: + +typedef struct _EFI_IFR_QUESTION_HEADER { + EFI_IFR_STATEMENT_HEADER Header; + EFI_QUESTION_ID QuestionId; + EFI_VARSTORE_ID VarStoreId; + union { + EFI_STRING_ID VarName; + UINT16 VarOffset; + } VarStoreInfo; + UINT8 Flags; +} EFI_IFR_QUESTION_HEADER; + +Members: +Header The standard statement header. +QuestionId The unique value that identifies the particular question being defined by the opcode. The value of zero is reserved. +Flags A bit-mask that determines which unique settings are active for this question. +VarStoreId Specifies the identifier of a previously declared variable store to use when storing the question’s value. + A value of zero indicates no associated variable store. +VarStoreInfo If VarStoreId refers to Buffer Storage (EFI_IFR_VARSTORE or EFI_IFR_VARSTORE_EFI), then VarStoreInfo contains a 16-bit Buffer Storage offset (VarOffset). + If VarStoreId refers to Name/Value Storage (EFI_IFR_VARSTORE_NAME_VALUE), then VarStoreInfo contains the String ID of the name (VarName) for this name/value pair. + +Description +This is the standard header for questions. +``` + +# Creating `efivarstore` + + + +FS0:\> dmpstore -all +``` +Variable NV+BS 'EF2ACC91-7B50-4AB9-AB67-2B04F8BC135E:HIIFormCheckboxEfiVarstore' DataSize = 0x01 + 00000000: 01 *.* +``` + +FS0:\> dmpstore -guid EF2ACC91-7B50-4AB9-AB67-2B04F8BC135E +Variable NV+BS 'EF2ACC91-7B50-4AB9-AB67-2B04F8BC135E:HIIFormCheckboxEfiVarstore' DataSize = 0x01 + 00000000: 01 *.* diff --git a/Lessons/Lesson_59/UefiLessonsPkg/DisplayHIIByGuid/DisplayHIIByGuid.c b/Lessons/Lesson_59/UefiLessonsPkg/DisplayHIIByGuid/DisplayHIIByGuid.c new file mode 100644 index 0000000..f1bf789 --- /dev/null +++ b/Lessons/Lesson_59/UefiLessonsPkg/DisplayHIIByGuid/DisplayHIIByGuid.c @@ -0,0 +1,69 @@ +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + +#include <Library/MemoryAllocationLib.h> +#include <Protocol/FormBrowser2.h> +#include <Library/HiiLib.h> + +INTN +EFIAPI +ShellAppMain ( + IN UINTN Argc, + IN CHAR16 **Argv + ) +{ + if (Argc <=1) { + Print(L"Usage:\n"); + Print(L" DisplayHIIByGuid <GUID> [<GUID> [<GUID> [...]]]\n"); + return EFI_INVALID_PARAMETER; + } + + GUID* Guids = (GUID*)AllocatePool(sizeof(GUID)*(Argc-1)); + + for (UINTN i=1; i<Argc; i++) { + RETURN_STATUS Status = StrToGuid(Argv[i], &Guids[i-1]); + if (Status != RETURN_SUCCESS) { + Print(L"Error! Can't convert one of the GUIDs to string\n"); + FreePool(Guids); + return EFI_INVALID_PARAMETER; + } + Print(L"%g\n", Guids[i-1]); + } + + + EFI_HII_HANDLE* Handle = HiiGetHiiHandles(&Guids[0]); + + UINTN HandleCount=0; + while (*Handle != NULL) { + Handle++; + HandleCount++; + Print(L"Total HandleCount=%d\n", HandleCount); + } + Print(L"Total HandleCount=%d\n", HandleCount); + +/* + return EFI_SUCCESS; + + EFI_STATUS Status; + EFI_FORM_BROWSER2_PROTOCOL* FormBrowser2; + Status = gBS->LocateProtocol(&gEfiFormBrowser2ProtocolGuid, NULL, (VOID**)&FormBrowser2); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = FormBrowser2->SendForm ( + FormBrowser2, + Handle, + 1, + NULL, + 0, + NULL, + NULL + ); + +*/ + FreePool(Handle); + FreePool(Guids); + + return EFI_SUCCESS; +} diff --git a/Lessons/Lesson_59/UefiLessonsPkg/DisplayHIIByGuid/DisplayHIIByGuid.inf b/Lessons/Lesson_59/UefiLessonsPkg/DisplayHIIByGuid/DisplayHIIByGuid.inf new file mode 100644 index 0000000..d8e97ad --- /dev/null +++ b/Lessons/Lesson_59/UefiLessonsPkg/DisplayHIIByGuid/DisplayHIIByGuid.inf @@ -0,0 +1,23 @@ +[Defines] + INF_VERSION = 1.25 + BASE_NAME = DisplayHIIByGuid + FILE_GUID = 1597e1d0-7f62-4631-a166-703f03bd7223 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +[Sources] + DisplayHIIByGuid.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + ShellCEntryLib + HiiLib + +[Protocols] + gEfiFormBrowser2ProtocolGuid diff --git a/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/Form.vfr b/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/Form.vfr new file mode 100644 index 0000000..780790e --- /dev/null +++ b/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/Form.vfr @@ -0,0 +1,25 @@ +#include <Uefi/UefiMultiPhase.h> + +#define FORMSET_GUID {0xef2acc91, 0x7b50, 0x4ab9, {0xab, 0x67, 0x2b, 0x4, 0xf8, 0xbc, 0x13, 0x5e}} + +formset + guid = FORMSET_GUID, + title = STRING_TOKEN(FORMSET_TITLE), + help = STRING_TOKEN(FORMSET_HELP), + + efivarstore UINT8, + attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + name = HIIFormCheckboxEfiVarstore, + guid = FORMSET_GUID; + + form + formid = 1, + title = STRING_TOKEN(FORMID1_TITLE); + + checkbox + varid = HIIFormCheckboxEfiVarstore, + prompt = STRING_TOKEN(CHECKBOX_PROMPT), + help = STRING_TOKEN(CHECKBOX_HELP), + endcheckbox; + endform; +endformset; diff --git a/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/HIIFormCheckbox.c b/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/HIIFormCheckbox.c new file mode 100644 index 0000000..5bfcab5 --- /dev/null +++ b/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/HIIFormCheckbox.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com> + * + * SPDX-License-Identifier: MIT + */ + +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiLib.h> + +#include <Library/HiiLib.h> +#include <Protocol/FormBrowser2.h> + +#include <Library/DevicePathLib.h> +#include <Library/BaseMemoryLib.h> + +extern UINT8 FormBin[]; + +#pragma pack(1) +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; +#pragma pack() + +#define FORMSET_GUID {0xef2acc91, 0x7b50, 0x4ab9, {0xab, 0x67, 0x2b, 0x4, 0xf8, 0xbc, 0x13, 0x5e}} + +EFI_HII_HANDLE mHiiHandle = NULL; +EFI_HANDLE mDriverHandle = NULL; + +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_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + // + // Publish sample Fromset + // + Status = gBS->InstallProtocolInterface ( + &mDriverHandle, + &gEfiDevicePathProtocolGuid, + EFI_NATIVE_INTERFACE, + &mHiiVendorDevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + + + UINTN BufferSize; + UINT8 EfiVarstore; + BufferSize = sizeof(UINT8); + Status = gRT->GetVariable ( + L"HIIFormCheckboxEfiVarstore", + &mHiiVendorDevicePath.VendorDevicePath.Guid, + NULL, + &BufferSize, + &EfiVarstore); + if (EFI_ERROR(Status)) { + Print(L"Error! Can't find variable! %r\n", Status); + ZeroMem(&EfiVarstore, sizeof(EfiVarstore)); + Status = gRT->SetVariable( + L"HIIFormCheckboxEfiVarstore", + &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); + } + } + + + EFI_HII_HANDLE Handle = HiiAddPackages( + &gEfiCallerIdGuid, + mDriverHandle, + HIIFormCheckboxStrings, + FormBin, + NULL + ); + if (Handle == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + EFI_FORM_BROWSER2_PROTOCOL* FormBrowser2; + Status = gBS->LocateProtocol(&gEfiFormBrowser2ProtocolGuid, NULL, (VOID**)&FormBrowser2); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = FormBrowser2->SendForm ( + FormBrowser2, + &Handle, + 1, + NULL, + 0, + NULL, + NULL + ); + + HiiRemovePackages(Handle); + + return EFI_SUCCESS; +} diff --git a/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/HIIFormCheckbox.inf b/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/HIIFormCheckbox.inf new file mode 100644 index 0000000..d0b9f91 --- /dev/null +++ b/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/HIIFormCheckbox.inf @@ -0,0 +1,30 @@ +## +# Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com> +# +# SPDX-License-Identifier: MIT +## + +[Defines] + INF_VERSION = 1.25 + BASE_NAME = HIIFormCheckbox + FILE_GUID = 771a4631-43ba-4852-9593-919d9de079f1 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +[Sources] + HIIFormCheckbox.c + Strings.uni + Form.vfr + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + HiiLib + +[Protocols] + gEfiFormBrowser2ProtocolGuid
\ No newline at end of file diff --git a/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/Strings.uni b/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/Strings.uni new file mode 100644 index 0000000..7788773 --- /dev/null +++ b/Lessons/Lesson_59/UefiLessonsPkg/HIIFormCheckbox/Strings.uni @@ -0,0 +1,13 @@ +// +// 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" |