Skip to content

Latest commit

 

History

History

Lesson_Hidden_BIOS_settings

In this lesson we would investigate how to modify hidden BIOS settings. "Hidden" in this context means settings from the menu that are not selectable for modification or settings that are even not shown in the menu. In other words settings that are closed by grayoutif or suppressif in the VFR code.

For this lesson I've created a HiddenSettings driver that populates VFR elements hidden with both these methods. To show that we can modify settings regardless of their underlying storage type, the driver populates both varstore elements and efivarstore elements.

You can find the source code for the driver at the end of this lesson. But right now let's imagine that we now nothing about it.

When the driver is loaded:

FS0:\> load HiddenSettings.efi
Image 'FS0:\HiddenSettings.efi' loaded at 61F9000 - Success

It populates the following formset:

FormsetInTheMenu

If you enter this form, you would see this:

Form1

As you can see no settings are available for modification. So what can we do in such case?

General plan

  • Dump package lists with form packages,
  • "Disifr" (analogy with "disassemble", since readable VFR code is compiled to IFR machine code) package lists with form packages and find necessary hidden settings,
  • Use HIIConfig.efi application to modify settings

Dump package lists with form packages

We already have a ShowHII application that allows us to see all package lists in the HII database. Let's modify it a little bit to give us an opportunity to save them. To not interfere with the previous lesson I've created a new ShowHIIext (extended) application with the necessary modifications. I won't go into the details, since we already know all the building blocks for such changes.

Here is a final help for the ShowHIIext application:

FS0:\> ShowHIIext.efi -?
Shows packages installed into the HII database.

SHOWHIIEXT [-b] [save [<index>]]

  -b            - Display one screen at a time
  save          - Save all package lists as files
  save <index>  - Save package list with index <index> as a file

We can first execute it without arguments, find the package lists in the output which have packages of FORMS type and then use the application again with save <index> options to save only the necessary package lists.

But to make things simplier and faster let's save all the available package lists and deal with them later. Don't forget to load our HiddenSettings.efi driver first!

FS0:\> load HiddenSettings.efi
Image 'FS0:\HiddenSettings.efi' loaded at 640A000 - Success
FS0:\> ShowHIIext.efi save
Save file as 0000_A487A478-51EF-48AA-8794-7BEE2A0562F1
Save file as 0001_19618BCE-55AE-09C6-37E9-4CE04084C7A1
Save file as 0002_2F30DA26-F51B-4B6F-85C4-31873C281BCA
Save file as 0003_F74D20EE-37E7-48FC-97F7-9B1047749C69
Save file as 0004_EBF8ED7C-0DD1-4787-84F1-F48D537DCACF
Save file as 0005_FE561596-E6BF-41A6-8376-C72B719874D0
Save file as 0006_2A46715F-3581-4A55-8E73-2B769AAA30C5
Save file as 0007_99FDC8FD-849B-4EBA-AD13-FB9699C90A4D
Save file as 0008_E38C1029-E38F-45B9-8F0D-E2E60BC9B262
Save file as 0009_D9DCC5DF-4007-435E-9098-8970935504B2
Save file as 0010_F5F219D3-7006-4648-AC8D-D61DFB7BC6AD
Save file as 0011_4B47D616-A8D6-4552-9D44-CCAD2E0F4CF9
Save file as 0012_F95A7CCC-4C55-4426-A7B4-DC8961950BAE
Save file as 0013_DEC5DAA4-6781-4820-9C63-A7B0E4F1DB31
Save file as 0014_4344558D-4EF9-4725-B1E4-3376E8D6974F
Save file as 0015_0AF0B742-63EC-45BD-8DB6-71AD7F2FE8E8
Save file as 0016_25F200AA-D3CB-470A-BF51-E7D162D22E6F
Save file as 0017_5F5F605D-1583-4A2D-A6B2-EB12DAB4A2B6
Save file as 0018_F3D301BB-F4A5-45A8-B0B7-FA999C6237AE
Save file as 0019_7C04A583-9E3E-4F1C-AD65-E05268D0B4D1
Save file as 0020_269D7962-BADC-44DA-815A-4AF4F293F3E0

"Disifr" package lists with form packages and find necessary hidden settings

Now when we have all the package lists, let's try to extract UEFI IFR data from the binaries and transform it into human-readable text.

Luckily for us such tool already exists.

Initially it was developed by @donovan6000 and called Universal-IFR-Extractor. The development was discontinued and picked up in the fork by @NikolajSchlej. As a final iteration @NikolajSchlej has decided to rewrite the utility to Rust language, and at the time of this writing it can be considered as a most up-to-date version of the utility - IFRExtractor-RS. So this is a program that we would be using to find our hidden settings.

Since the application is written in Rust don't forget to install cargo (the Rust package manager):

$ sudo apt install cargo

Now let's clone and build IFRExtractor-RS application:

$ git clone https://github.com/LongSoft/IFRExtractor-RS
$ cd IFRExtractor-RS
$ cargo build
    Updating crates.io index
  Downloaded version_check v0.1.5
  Downloaded memchr v2.5.0
  Downloaded nom v4.2.3
  Downloaded 3 crates (189.3 KB) in 0.81s
   Compiling version_check v0.1.5
   Compiling memchr v2.5.0
   Compiling nom v4.2.3
   Compiling ifrextractor v1.1.0 (/home/<...>/IFRExtractor-RS)
    Finished dev [unoptimized + debuginfo] target(s) in 1m 02s

The final binary would be created in the target/debug folder, and here is a help of the generated ifrextractor utility:

$ ./target/debug/ifrextractor
IFRExtractor RS v1.1.0 - extracts HII database from binary files into human-readable text
Usage: ifrextractor file.bin

If you want to, you can test ifrextractor on any of our previously generated drivers that populate forms to better understand its output. But I think we can just use it now in our investigation and understand its output along the way.

Let's launch ifrextractor on every generated package list file:

$ find ~/disk/ -name "00*_*" -type f -exec ./target/debug/ifrextractor {} \;
Extracting all UEFI HII form packages using en-US UEFI HII string packages
No IFR data found
No IFR data found
No IFR data found
No IFR data found
No IFR data found
No IFR data found
Extracting all UEFI HII form packages using en-US UEFI HII string packages
No IFR data found
Extracting all UEFI HII form packages using en-US UEFI HII string packages
No IFR data found
No IFR data found
No IFR data found
No IFR data found
No IFR data found
No IFR data found
No IFR data found
Extracting all UEFI HII form packages using en-US UEFI HII string packages
Extracting all UEFI HII form packages using en-US UEFI HII string packages
No IFR data found
Extracting all UEFI HII form packages using en-US UEFI HII string packages

As you can see for every file with the IFR data inside the ifrextractor has created a *.txt file with the decoded form data.

$ ls ~disk/*.txt
disk/0004_EBF8ED7C-0DD1-4787-84F1-F48D537DCACF.0.0.en-US.ifr.txt
disk/0004_EBF8ED7C-0DD1-4787-84F1-F48D537DCACF.1.0.en-US.ifr.txt
disk/0005_FE561596-E6BF-41A6-8376-C72B719874D0.0.0.en-US.ifr.txt
disk/0006_2A46715F-3581-4A55-8E73-2B769AAA30C5.0.0.en-US.ifr.txt
disk/0009_D9DCC5DF-4007-435E-9098-8970935504B2.0.0.en-US.ifr.txt
disk/0011_4B47D616-A8D6-4552-9D44-CCAD2E0F4CF9.0.0.en-US.ifr.txt
disk/0020_269D7962-BADC-44DA-815A-4AF4F293F3E0.0.0.en-US.ifr.txt

Let's grep the name of our target formset that we saw in the menu in these files:

$ grep "Form with hidden settings" ~/disk/*.txt
../20_269D7962-BADC-44DA-815A-4AF4F293F3E0.0.0.en-US.ifr.txt:   Form FormId: 0x1, Title: "Form with hidden settings"

Now let's investigate this file:

$ cat disk/0020_269D7962-BADC-44DA-815A-4AF4F293F3E0.0.0.en-US.ifr.txt
Program version: 1.5.1, Extraction mode: UEFI
FormSet Guid: 98259761-6B0B-4531-A74B-67AF5D8A8153, Title: "Formset with hidden settings", Help: "Formset with hidden settings"
        DefaultStore DefaultId: 0x0, Name: "Standard default"
        DefaultStore DefaultId: 0x1, Name: ""
        VarStore Guid: 3F5996A7-8B56-472C-9538-475F77157C84, VarStoreId: 0x1, Size: 0x4, Name: "FormData"
        VarStoreEfi Guid: 01539E15-2A73-4AAF-9D3E-437BFABB4666, VarStoreId: 0x2, Attributes: 0x3, Size: 0x4, Name: "FormEfiData"
        Form FormId: 0x1, Title: "Form with hidden settings"
                SuppressIf
                        True
                        CheckBox Prompt: "Show varstore settings", Help: "Show varstore settings", QuestionFlags: 0x0, QuestionId: 0x1, VarStoreId: 0x1, VarOffset: 0x0, Flags: 0x0, Default: Disabled, MfgDefault: Disabled
                                Default DefaultId: 0x0 Value: 0
                        End
                End
                SuppressIf
                        EqIdVal QuestionId: 0x1, Value: 0x0
                        Numeric Prompt: "Numeric prompt", Help: "Numeric help", QuestionFlags: 0x0, QuestionId: 0x2, VarStoreId: 0x1, VarOffset: 0x1, Flags: 0x21, Size: 16, Min: 0x0, Max: 0xA, Step: 0x1
                                Default DefaultId: 0x0 Value: 5
                        End
                        OneOf Prompt: "OneOf list prompt", Help: "OneOf list help", QuestionFlags: 0x0, QuestionId: 0x3, VarStoreId: 0x1, VarOffset: 0x3, Flags: 0x10, Size: 8, Min: 0x0, Max: 0x55, Step: 0x0
                                OneOfOption Option: "OneOf list option 1" Value: 0
                                OneOfOption Option: "OneOf list option 2" Value: 51, Default
                                OneOfOption Option: "OneOf list option 3" Value: 85
                        End
                End
                GrayOutIf
                        True
                        CheckBox Prompt: "Enable efivarstorage settings", Help: "Enable efivarstorage settings", QuestionFlags: 0x0, QuestionId: 0x4, VarStoreId: 0x2, VarOffset: 0x0, Flags: 0x0, Default: Disabled, MfgDefault: Disabled
                                Default DefaultId: 0x0 Value: 0
                        End
                End
                GrayOutIf
                        EqIdVal QuestionId: 0x4, Value: 0x0
                        Numeric Prompt: "Numeric EFI prompt", Help: "Numeric EFI help", QuestionFlags: 0x0, QuestionId: 0x5, VarStoreId: 0x2, VarOffset: 0x1, Flags: 0x21, Size: 16, Min: 0x0, Max: 0xA, Step: 0x1
                                Default DefaultId: 0x0 Value: 6
                        End
                        OneOf Prompt: "OneOf list EFI prompt", Help: "OneOf list EFI help", QuestionFlags: 0x0, QuestionId: 0x6, VarStoreId: 0x2, VarOffset: 0x3, Flags: 0x10, Size: 8, Min: 0x0, Max: 0x55, Step: 0x0
                                OneOfOption Option: "OneOf list option 1" Value: 0
                                OneOfOption Option: "OneOf list option 2" Value: 51
                                OneOfOption Option: "OneOf list option 3" Value: 85, Default
                        End
                End
        End
End

Here we can see 2 groups of settings:

  • suppressed TRUE checkbox [varstore] that unlocks the 2 settings below:

    • numeric option [varstore]
    • oneof option [varstore]
  • grayoutif TRUE checkbox [efivarstore] that unlocks the 2 settings below:

    • numeric option [efivarstore]
    • oneof option [efivarstore]

Now when we know everything about out target form, let's try to modify its hidden settings.

Use HIIConfig.efi application to modify settings

As you can see from the 20_269D7962-BADC-44DA-815A-4AF4F293F3E0.0.0.en-US.ifr.txt output, the hidden settings are stored in these varstore/efivarstore elements:

  • VarStore Guid: 3F5996A7-8B56-472C-9538-475F77157C84, VarStoreId: 0x1, Size: 0x4, Name: "FormData"
  • VarStoreEfi Guid: 01539E15-2A73-4AAF-9D3E-437BFABB4666, VarStoreId: 0x2, Attributes: 0x3, Size: 0x4, Name: "FormEfiData"

Now if you look at VarStoreId/VarOffset fields in form elements description, you can recreate the storages internal structure:

Element Menu string VarStoreId VarOffset (in bytes) Size (in bytes)
Checkbox "Show varstore settings" 1 0 1 byte (implicitly since it is a checkbox)
Numeric "Numeric prompt" 1 1 2 bytes (since element has Size: 16)
OneOf "OneOf list prompt" 1 3 1 bytes (since element has Size: 8)
Checkbox "Enable efivarstorage settings" 2 0 1 byte (implicitly since it is a checkbox)
Numeric "Numeric EFI prompt" 2 1 2 bytes (since element has Size: 16)
OneOf "OneOf list EFI prompt" 2 3 1 bytes (since element has Size: 8)

You can use HIIConfig.efi dump to print all the HII database settings. If you'll search for the varstore GUID, you'll find the following settings:

GUID=a796593f568b2c479538475f77157c84 (3F5996A7-8B56-472C-9538-475F77157C84)
NAME=0046006f0072006d0044006100740061 (FormData)
PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400 (VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB))
OFFSET=0  WIDTH=0000000000000004  VALUE=33000500
00 05 00 33                                      | ...3

GUID=a796593f568b2c479538475f77157c84 (3F5996A7-8B56-472C-9538-475F77157C84)
NAME=0046006f0072006d0044006100740061 (FormData)
PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400 (VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB))
ALTCFG=0000
OFFSET=0000  WIDTH=0001  VALUE=00
00                                               | .
OFFSET=0001  WIDTH=0002  VALUE=0005
05 00                                            | ..
OFFSET=0003  WIDTH=0001  VALUE=33
33                                               | 3

GUID=a796593f568b2c479538475f77157c84 (3F5996A7-8B56-472C-9538-475F77157C84)
NAME=0046006f0072006d0044006100740061 (FormData)
PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400 (VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB))
ALTCFG=0001
OFFSET=0000  WIDTH=0001  VALUE=00
00                                               | .
OFFSET=0001  WIDTH=0002  VALUE=0005
05 00                                            | ..
OFFSET=0003  WIDTH=0001  VALUE=33
33                                               | 3

Here you can see that the current FormData varstorage values are currently equal to their defaults:

  • FormData.Checkbox["Show varstore settings"] = 0
  • FormData.Numeric["Numeric prompt"] = 0005
  • FromData.OneOf["OneOf list prompt"] = 33

Also we can grab the PATH value from the output (VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB)) and use it in HIIConfig.efi route/HIIConfig.efi extract command calls.

Unfortunately the efivarstore settings are not present in the output, since the implementation of the EFI_HII_CONFIG_ROUTING_PROTOCOL.ExportConfig() is buggy in the current edk2 code (https://bugzilla.tianocore.org/show_bug.cgi?id=4639). But we'll deal with it later. Now let's focus on the varstorage elements.

Let's show the current settings for the "Show varstore settings" checkbox:

FS0:\> HIIConfig.efi extract 3F5996A7-8B56-472C-9538-475F77157C84 FormData VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB)

Request: GUID=a796593f568b2c479538475f77157c84&NAME=0046006f0072006d0044006100740061&PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400
Response: GUID=a796593f568b2c479538475f77157c84&NAME=0046006f0072006d0044006100740061&PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400&OFFSET=0000&WIDTH=0001&VALUE=00&OFFSET=0001&WIDTH=0002&VALUE=0005&OFFSET=0003&WIDTH=0001&VALUE=33&GUID=a796593f568b2c479538475f77157c84&NAME=0046006f0072006d0044006100740061&PATH=01041<...>


GUID=a796593f568b2c479538475f77157c84 (3F5996A7-8B56-472C-9538-475F77157C84)
NAME=0046006f0072006d0044006100740061 (FormData)
PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400 (VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB))
OFFSET=0000  WIDTH=0001  VALUE=00
00                                               | .
OFFSET=0001  WIDTH=0002  VALUE=0005
05 00                                            | ..
OFFSET=0003  WIDTH=0001  VALUE=33
33                                               | 3

GUID=a796593f568b2c479538475f77157c84 (3F5996A7-8B56-472C-9538-475F77157C84)
NAME=0046006f0072006d0044006100740061 (FormData)
PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400 (VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB))
ALTCFG=0000
OFFSET=0000  WIDTH=0001  VALUE=00
00                                               | .
OFFSET=0001  WIDTH=0002  VALUE=0005
05 00                                            | ..
OFFSET=0003  WIDTH=0001  VALUE=33
33                                               | 3

GUID=a796593f568b2c479538475f77157c84 (3F5996A7-8B56-472C-9538-475F77157C84)
NAME=0046006f0072006d0044006100740061 (FormData)
FS0:\> 041400975b3d3fe8484a4f851e82e650930aeb7fff0400 (VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB))
ALTCFG=0001
OFFSET=0000  WIDTH=0001  VALUE=00
00                                               | .
OFFSET=0001  WIDTH=0002  VALUE=0005
05 00                                            | ..
OFFSET=0003  WIDTH=0001  VALUE=33
33                                               | 3

The output for the setting is practically the same as in the HIIConfig.efi dump output, but with that command we've verified that we can successfully get individual setting.

Now let's enable the checkbox:

FS0:\> HIIConfig.efi route 3F5996A7-8B56-472C-9538-475F77157C84 FormData VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB) 0000 0001 01

Request: GUID=a796593f568b2c479538475f77157c84&NAME=0046006f0072006d0044006100740061&PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400&OFFSET=0000&WIDTH=0001&VALUE=01

You can verify that the suppressed settings are now shown in the driver form!

Form2

Now let's think what we can do about efivarstore settings.

Because of the aforementioned bug we can't export evivarstore settings with the HIIConfig.efi dump, but we still can try to extract/route them. The problem is that to use HIIConfig extract/route we need to know DevicePath of the storage. Since our varstore and efivarstore are created by the same driver, let's try to use the same VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB) to extract "Enable efivarstorage settings" checkbox:

FS0:\> HIIConfig.efi extract 01539E15-2A73-4AAF-9D3E-437BFABB4666 FormEfiData VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB)

Request: GUID=159e5301732aaf4a9d3e437bfabb4666&NAME=0046006f0072006d0045006600690044006100740061&PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400
Response: GUID=159e5301732aaf4a9d3e437bfabb4666&NAME=0046006f0072006d0045006600690044006100740061&PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400&OFFSET=0000&WIDTH=0001&VALUE=01&OFFSET=0001&WIDTH=0002&VALUE=0002&OFFSET=0003&WIDTH=0001&VALUE=00&GUID=159e5301732aaf4a9d3e437bfabb4666&NAME=0046006f0072006d004500660069004<...>


GUID=159e5301732aaf4a9d3e437bfabb4666 (01539E15-2A73-4AAF-9D3E-437BFABB4666)
NAME=0046006f0072006d0045006600690044006100740061 (FormEfiData)
PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400 (VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB))
OFFSET=0000  WIDTH=0001  VALUE=00
00                                               | .
OFFSET=0001  WIDTH=0002  VALUE=0006
06 00                                            | ..
OFFSET=0003  WIDTH=0001  VALUE=55
55                                               | U

GUID=159e5301732aaf4a9d3e437bfabb4666 (01539E15-2A73-4AAF-9D3E-437BFABB4666)
NAME=0046006f0072006d0045006600690044006100740061 (FormEfiData)
PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400 (VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB))
ALTCFG=0000
OFFSET=0000  WIDTH=0001  VALUE=00
00                                               | .
OFFSET=0001  WIDTH=0002  VALUE=0006
06 00                                            | ..
OFFSET=0003  WIDTH=0001  VALUE=55
55                                               | U

GUID=159e5301732aaf4a9d3e437bfabb4666 (01539E15-2A73-4AAF-9D3E-437BFABB4666)
NAME=0046006f0072006d0045006600690044006100740061 (FormEfiData)
FS0:\> 041400975b3d3fe8484a4f851e82e650930aeb7fff0400 (VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB))
ALTCFG=0001
OFFSET=0000  WIDTH=0001  VALUE=00
00                                               | .
OFFSET=0001  WIDTH=0002  VALUE=0006
06 00                                            | ..
OFFSET=0003  WIDTH=0001  VALUE=55
55                                               | U

Luckilly in this particular case we were able to find efivarstore settings. If it is not the case we'll discuss alternative way in the Another way to change 'efivarstore' settings paragraph below.

Let's try to change "Enable efivarstorage settings" checkbox value:

FS0:\> HIIConfig.efi route 01539E15-2A73-4AAF-9D3E-437BFABB4666 FormEfiData VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB) 0000 0001 01

Request: GUID=159e5301732aaf4a9d3e437bfabb4666&NAME=0046006f0072006d0045006600690044006100740061&PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400&OFFSET=0000&WIDTH=0001&VALUE=01

Now exit to the menu and see our changes:

Form3

As you can see we now able to see both grayoutif and suppressif hidden settings. Now you can successfully modify the necessary settings via the menu!

What if the settings can't be shown in the menu?

In our example by setting the checkboxes we've opened the hidden settings for modification from the menu directly. But that is not always the case, sometimes there is no such checkboxes, and the hidden settings are always suppressed/grayout via suppressif TRUE/grayoutif TRUE statements.

In such cases you can use HIIConfig.efi route to modify the necessary settings directly and verify the changes via the HIIConfig.efi extract.

For example let's modify FromData.OneOf["OneOf list prompt"] from option2 to option3 and FromData.Numeric["Numeric EFI prompt"] from 6 to 3.

FS0:\> HIIConfig.efi route 3F5996A7-8B56-472C-9538-475F77157C84 FormData VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB) 0003 0001 55
Request: GUID=a796593f568b2c479538475f77157c84&NAME=0046006f0072006d0044006100740061&PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400&OFFSET=0003&WIDTH=0001&VALUE=55
FS0:\> HIIConfig.efi route 01539E15-2A73-4AAF-9D3E-437BFABB4666 FormEfiData VenHw(3F3D5B97-48E8-4F4A-851E-82E650930AEB) 0001 0002 0003
Request: GUID=159e5301732aaf4a9d3e437bfabb4666&NAME=0046006f0072006d0045006600690044006100740061&PATH=01041400975b3d3fe8484a4f851e82e650930aeb7fff0400&OFFSET=0001&WIDTH=0002&VALUE=0003

If you'll enter the form now, you'll see that the values were successfully updated:

Form4

Another way to change efivarstore settings

Because of the bug in the edk2 code of the EFI_HII_CONFIG_ROUTING_PROTOCOL.ExportConfig() implementation we can't dump efivarstore storages and therefore get their device path. In the example above we've got lucky and were able to just use devicepath from the neighboor varstore storage. But what we can do if it is not the case and efivarstore has unknown device path?

In this case we can utilize shell command dmpstore to dump and modify efivarstore underlying EFI variable directly. From the earlier lessons we already know how to change EFI variables like that, but for completeness of this lesson let's repeat the process step by step.

To show the current values inside the storage we can use:

FS0:\> dmpstore -guid 01539E15-2A73-4AAF-9D3E-437BFABB4666
Variable NV+BS '01539E15-2A73-4AAF-9D3E-437BFABB4666:FormEfiData' DataSize = 0x04
  00000000: 01 03 00 55                                      *...U*

Now let's save the dump

FS0:\> dmpstore -guid 01539E15-2A73-4AAF-9D3E-437BFABB4666 -s FormEfiData
Save variable to file: FormEfiData.
Variable NV+BS '01539E15-2A73-4AAF-9D3E-437BFABB4666:FormEfiData' DataSize = 0x04

And update it via the shell hexedit command:

FS0:\> hexedit FormEfiData

The storage settings are near the end of the file: dmpstore1

Modify 0300 to 0700 to change the value of the numeric option:

dmpstore2

Now use Ctrl-S to save the updated buffer and Ctrl-Q to exit the editor.

As you might remember from earlier lessons to correctly load the updated variable we need to recalculate the checksum inside the file. For that we can use our UpdateDmpstoreDump.efi application that we have written earlier.

FS0:\> UpdateDmpstoreDump.efi FormEfiData

If you check the file now, you can see that the 4-byte checksum at the end was updated:

dmpstorer3

Now load the updated file to modify the EFI variable content:

FS0:\> dmpstore -guid 01539E15-2A73-4AAF-9D3E-437BFABB4666 -l FormEfiData
Load and set variables from file: FormEfiData.
Variable NV+BS '01539E15-2A73-4AAF-9D3E-437BFABB4666:FormEfiData' DataSize = 0x04

Exit to the form and verify that the changes are indeed present in the menu:

Form5

Updating hidden settings in the real world scenario

In this lesson we've investigated how we can find and modify hidden settings in the HII database. But I want to point out that when you find something like that in the real system there is no guarantee that the found settings are actually used in the UEFI code.

For example you've found an option "PCIe speed" and change it to "Gen1". When you reboot, the setting is persistent, so everything seems correct and you expect that PCIe now runs at Gen1 speed. But the problem is that you don't see any changes in the PCIe functionality. Unfortunately such scenario is possible. You are changing some options in the settings storage, but no one says that these settings are used in any way in the driver code.

But still worth a try!

Alternative tools for BIOS settings modification

In this lesson we've used ShowHIIext.efi/HIIConfig.efi/UpdateDmpstoreDump.efi applications to modify BIOS settings. These applications we've developed earlier from scratch.

But we are not the first ones who tries to tweak hidden BIOS settings.

Most know solution is using patched version of the GRUB bootloader. This patched version provides additional command setup_var and its variations that can be used to modify BIOS settings.

You can check the original solution by @datasone grub-mod-setup_var.

But right now it is adviced to use setup_var.efi instead. This is an advanced version of the program rewritten in Rust.

HiddenSettings driver code

As I promised here is a form code for the HiddenSettings driver.

UefiLessonsPkg/HiddenSettings/Form.vfr:

#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;

  efivarstore VARIABLE_STRUCTURE,
    attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    name  = FormEfiData,
    guid  = STORAGE_EFI_GUID;

  defaultstore StandardDefault,
    prompt      = STRING_TOKEN(STANDARD_DEFAULT_PROMPT),
    attribute   = 0x0000;

  form
    formid = 1,
    title = STRING_TOKEN(FORMID1_TITLE);

suppressif TRUE;
    checkbox
      varid = FormData.CheckboxValue,
      prompt = STRING_TOKEN(CHECKBOX_PROMPT),
      help = STRING_TOKEN(CHECKBOX_HELP),
      default = FALSE, defaultstore = StandardDefault,
    endcheckbox;
endif;

suppressif ideqval FormData.CheckboxValue == 0;
    numeric
      name = NumericQuestion,
      varid = FormData.NumericValue,
      prompt = STRING_TOKEN(NUMERIC_PROMPT),
      help = STRING_TOKEN(NUMERIC_HELP),
      flags = NUMERIC_SIZE_2 | DISPLAY_UINT_HEX,
      minimum = 0,
      maximum = 10,
      step = 1,
      default = 5, defaultstore = StandardDefault,
    endnumeric;

    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 = DEFAULT;
      option text = STRING_TOKEN(ONEOF_OPTION3), value = 0x55, flags = 0;
    endoneof;
endif;

grayoutif TRUE;
    checkbox
      varid = FormEfiData.CheckboxValue,
      prompt = STRING_TOKEN(CHECKBOX_EFI_PROMPT),
      help = STRING_TOKEN(CHECKBOX_EFI_HELP),
      default = FALSE, defaultstore = StandardDefault,
    endcheckbox;
endif;

grayoutif ideqval FormEfiData.CheckboxValue == 0;
    numeric
      name = NumericEfiQuestion,
      varid = FormEfiData.NumericValue,
      prompt = STRING_TOKEN(NUMERIC_EFI_PROMPT),
      help = STRING_TOKEN(NUMERIC_EFI_HELP),
      flags = NUMERIC_SIZE_2 | DISPLAY_UINT_HEX,
      minimum = 0,
      maximum = 10,
      step = 1,
      default = 6, defaultstore = StandardDefault,
    endnumeric;

    oneof
      name = OneOfEfiQuestion,
      varid = FormEfiData.OneOfValue,
      prompt = STRING_TOKEN(ONEOF_EFI_PROMPT),
      help = STRING_TOKEN(ONEOF_EFI_HELP),
      option text = STRING_TOKEN(ONEOF_OPTION1), value = 0x00, flags = 0;
      option text = STRING_TOKEN(ONEOF_OPTION2), value = 0x33, flags = 0;
      option text = STRING_TOKEN(ONEOF_OPTION3), value = 0x55, flags = DEFAULT;
    endoneof;
endif;

  endform;
endformset;

UefiLessonsPkg/HiddenSettings/Data.h:

#ifndef _DATA_H_
#define _DATA_H_

#define FORMSET_GUID  {0x98259761, 0x6b0b, 0x4531, {0xa7, 0x4b, 0x67, 0xaf, 0x5d, 0x8a, 0x81, 0x53}}
#define DATAPATH_GUID {0x3f3d5b97, 0x48e8, 0x4f4a, {0x85, 0x1e, 0x82, 0xe6, 0x50, 0x93, 0x0a, 0xeb}}
#define STORAGE_GUID  {0x3f5996a7, 0x8b56, 0x472c, {0x95, 0x38, 0x47, 0x5f, 0x77, 0x15, 0x7c, 0x84}}
#define STORAGE_EFI_GUID  {0x01539e15, 0x2a73, 0x4aaf, {0x9d, 0x3e, 0x43, 0x7b, 0xfa, 0xbb, 0x46, 0x66}}

#pragma pack(1)
typedef struct {
  UINT8 CheckboxValue;
  UINT16 NumericValue;
  UINT8 OneOfValue;
} VARIABLE_STRUCTURE;
#pragma pack()

#endif

You can compare the original VFR with the decoded file from the ifrextractor. There is nothing unusual in the C source code file. But if you want to you can check the source code here.