aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons_uncategorized/Lesson_Hidden_BIOS_settings/README.md
blob: fb773f6c6a5282c00b99e76e4bd231146a880b1b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
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](FormsetInTheMenu.png?raw=true "FormsetInTheMenu")

If you enter this form, you would see this:

![Form1](Form1.png?raw=true "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](https://github.com/donovan6000/Universal-IFR-Extractor). The development was discontinued and picked up in the [fork](https://github.com/LongSoft/Universal-IFR-Extractor) 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](https://github.com/LongSoft/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](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](Form2.png?raw=true "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](Form3.png?raw=true "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](Form4.png?raw=true "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](dmpstore1.png?raw=true "dmpstore1")

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

![dmpstore2](dmpstore2.png?raw=true "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](dmpstore3.png?raw=true "dmpstore3")

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](Form5.png?raw=true "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](https://github.com/datasone/grub-mod-setup_var).

But right now it is adviced to use [setup_var.efi](https://github.com/datasone/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](/UefiLessonsPkg/HiddenSettings).