aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons/Lesson_68/README.md
blob: cfc9d72994c20d50fff7f6709dada35b4437c306 (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
# `oneof` element

`oneof` element allows to select an option from the predefined set (https://edk2-docs.gitbook.io/edk-ii-vfr-specification/2_vfr_description_in_bnf/211_vfr_form_definition#2.11.6.6.2-vfr-oneof-statement-definition)

Add the folowing code to the `UefiLessonsPkg/HIIFormDataElements/Form.vfr`
```
oneof
  varid = FormData.OneOfValue,
  prompt = STRING_TOKEN(ONEOF_PROMPT),
  help = STRING_TOKEN(ONEOF_HELP),
  option text = STRING_TOKEN(ONEOF_OPTION1), value = 0x00, flags = DEFAULT;
  option text = STRING_TOKEN(ONEOF_OPTION2), value = 0x33, flags = 0;
  option text = STRING_TOKEN(ONEOF_OPTION3), value = 0x55, flags = 0;
endoneof;
```

Add new string tokens to the `UefiLessonsPkg/HIIFormDataElements/Strings.uni`:
```
#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"
```

As for data, add this to the `UefiLessonsPkg/HIIFormDataElements/Data.h`:
```
typedef struct {
  ...
  UINT8 OneOf;
} UEFI_VARIABLE_STRUCTURE;
```

Once you load the form, you would get:

![OneOf1](OneOf1.png?raw=true "OneOf1")

You can select one of the available options:

![OneOf2](OneOf2.png?raw=true "OneOf2")

If you select the option 2:

![OneOf3](OneOf3.png?raw=true "OneOf3")

The variable field would get the value `0x33`. If you want to, you can verify it with the `dmpstore` command.

## IFR

IFR code would look like this (`Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements/DEBUG/Form.lst`):
```
    oneof
>000000B4: 05 91 0F 00 10 00 06 00 01 00 20 00 00 10 00 55 00
      varid = FormData.OneOfValue,
      prompt = STRING_TOKEN(0x000F),
      help = STRING_TOKEN(0x0010),
      option text = STRING_TOKEN(0x0011), value = 0x00, flags = DEFAULT;
>000000C5: 09 07 11 00 10 00 00
      option text = STRING_TOKEN(0x0012), value = 0x33, flags = 0;
>000000CC: 09 07 12 00 00 00 33
      option text = STRING_TOKEN(0x0013), value = 0x55, flags = 0;
>000000D3: 09 07 13 00 00 00 55
    endoneof;
>000000DA: 29 02
```

The first opcodes are:
```
EFI_IFR_ONE_OF

Summary:
Creates a select-one-of question.

Prototype:

#define EFI_IFR_ONE_OF_OP 0x05

typedef struct _EFI_IFR_ONE_OF {
 EFI_IFR_OP_HEADER Header;
 EFI_IFR_QUESTION_HEADER Question;
 UINT8 Flags;
 union {
 struct {
 UINT8 MinValue;
 UINT8 MaxValue;
 UINT8 Step;
 } u8;
 struct {
 UINT16 MinValue;
 UINT16 MaxValue;
 UINT16 Step;
 } u16;
 struct {
 UINT32 MinValue;
 UINT32 MaxValue;
 UINT32 Step;
 } u32;
 struct {
 UINT64 MinValue;
 UINT64 MaxValue;
 UINT64 Step;
 } u64;
 } data;
} EFI_IFR_ONE_OF;

Members:
Header 		The sequence that defines the type of opcode as well as the length of the opcode being defined.
		Header.OpCode = EFI_IFR_ONE_OF_OP.
Question 	The standard question header.
Flags 		Specifies flags related to the numeric question.
MinValue 	The minimum value to be accepted by the browser for this opcode.
		The size of the data field may vary from 8 to 64 bits, depending on the size specified in Flags
MaxValue 	The maximum value to be accepted by the browser for this opcode.
		The size of the data field may vary from 8 to 64 bits, depending on the size specified in Flags
Step 		Defines the amount to increment or decrement the value each time a user requests a value change.
		If the step value is 0, then the input mechanism for the numeric value is to be free-form
		and require the user to type in the actual value.
		The size of the data field may vary from 8 to 64 bits, depending on the size specified in Flags

Description:
This opcode creates a select-on-of object, where the user must select from one of the nested options.
This is identical to EFI_IFR_NUMERIC.
```

And here is a definition for the options opcodes:
```
EFI_IFR_ONE_OF_OPTION

Summary:
Creates a pre-defined option for a question.

Prototype:

#define EFI_IFR_ONE_OF_OPTION_OP 0x09

typedef struct _EFI_IFR_ONE_OF_OPTION {
 EFI_IFR_OP_HEADER Header;
 EFI_STRING_ID Option;
 UINT8 Flags;
 UINT8 Type;
 EFI_IFR_TYPE_VALUE Value;
} EFI_IFR_ONE_OF_OPTION;

Members:
Header	 The sequence that defines the type of opcode as well as the length of the opcode being defined.
	 Header.OpCode = EFI_IFR_ONE_OF_OPTION_OP.
Option   The string token reference to the option description string for this particular opcode.
Flags    Specifies the flags associated with the current option (EFI_IFR_OPTION_x)
Type 	 Specifies the type of the option’s value (See EFI_IFR_TYPE)
Value 	 The union of all of the different possible values. The actual contents (and size)
	 of the field depends on Type.
```

Description says that the content of the `Value` field is dependent on the value of the `Type` field. Here are all the possible value types with comments of their type flags:
```
typedef union {
 UINT8 u8;             // EFI_IFR_TYPE_NUM_SIZE_8
 UINT16 u16;           // EFI_IFR_TYPE_NUM_SIZE_16
 UINT32 u32;           // EFI_IFR_TYPE_NUM_SIZE_32
 UINT64 u64;           // EFI_IFR_TYPE_NUM_SIZE_64
 BOOLEAN b;            // EFI_IFR_TYPE_BOOLEAN
 EFI_HII_TIME time;    // EFI_IFR_TYPE_TIME
 EFI_HII_DATE date;    // EFI_IFR_TYPE_DATE
 EFI_STRING_ID string; // EFI_IFR_TYPE_STRING, EFI_IFR_TYPE_ACTION
 EFI_HII_REF ref;      // EFI_IFR_TYPE_REF
 // UINT8 buffer[];    // EFI_IFR_TYPE_BUFFER
} EFI_IFR_TYPE_VALUE;
```

And here are the actual values for the `EFI_IFR_TYPE_x` defines:
```
#define EFI_IFR_TYPE_NUM_SIZE_8 	0x00
#define EFI_IFR_TYPE_NUM_SIZE_16 	0x01
#define EFI_IFR_TYPE_NUM_SIZE_32 	0x02
#define EFI_IFR_TYPE_NUM_SIZE_64 	0x03
#define EFI_IFR_TYPE_BOOLEAN 		0x04
#define EFI_IFR_TYPE_TIME 		0x05
#define EFI_IFR_TYPE_DATE 		0x06
#define EFI_IFR_TYPE_STRING 		0x07
#define EFI_IFR_TYPE_OTHER 		0x08
#define EFI_IFR_TYPE_UNDEFINED 		0x09
#define EFI_IFR_TYPE_ACTION 		0x0A
#define EFI_IFR_TYPE_BUFFER 		0x0B
#define EFI_IFR_TYPE_REF 		0x0C
```

In our structure we've declared data as `UINT8 OneOf`. Therefore compiler automatically have deducted our type flag as `EFI_IFR_TYPE_NUM_SIZE_8`. If we change that to `UINT16 OneOf`, compiler would change the type field value to the `EFI_IFR_TYPE_NUM_SIZE_16`.

Compare this output with the one that we had before:
```
    oneof
>000000B4: 05 94 0F 00 10 00 06 00 01 00 20 00 00 11 00 00 55 00 00 00
      varid = FormData.OneOfValue,
      prompt = STRING_TOKEN(0x000F),
      help = STRING_TOKEN(0x0010),
      option text = STRING_TOKEN(0x0011), value = 0x00, flags = DEFAULT;
>000000C8: 09 08 11 00 11 01 00 00
      option text = STRING_TOKEN(0x0012), value = 0x33, flags = 0;
>000000D0: 09 08 12 00 01 01 33 00
      option text = STRING_TOKEN(0x0013), value = 0x55, flags = 0;
>000000D8: 09 08 13 00 01 01 55 00
    endoneof;
>000000E0: 29 02
```

Although `EFI_IFR_TYPE_VALUE` can take many values besides numeric if you try to set its type to the `EFI_HII_DATE OneOfValue` for example, you would get an error:
```
ERROR 12288: OneOf question only support UINT8, UINT16, UINT32 and UINT64 data type
```

So only subtype of `EFI_IFR_TYPE_VALUE` is supported.

# `orderedlist` element

Another element with options is the `orderedlist` element (https://edk2-docs.gitbook.io/edk-ii-vfr-specification/2_vfr_description_in_bnf/211_vfr_form_definition#2.11.6.8-vfr-orderedlist-statement-definition)

Add this to the `UefiLessonsPkg/HIIFormDataElements/Form.vfr`:
```
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;
endlist;
```

Add strings to the `UefiLessonsPkg/HIIFormDataElements/Strings.uni`:
```
#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"
```

If we have 3 options, we need to declare array of 3 elements. Let's declare them as `UINT8`:
```
typedef struct {
  ...
  UINT8 OrderedListValue[3];
} UEFI_VARIABLE_STRUCTURE;
```

On load our form would look like this:

![Orderedlist1](Orderedlist1.png?raw=true "Orderedlist1")

If you select the element:

![Orderedlist2](Orderedlist2.png?raw=true "Orderedlist2")

You can change its order by moving it up or down with the help of `+` and `-` keys:

![Orderedlist3](Orderedlist3.png?raw=true "Orderedlist3")

Change order to `2 1 3` and save it with `F10`:

![Orderedlist4](Orderedlist4.png?raw=true "Orderedlist4")

This would get the following data in the `OrderedListValue` field of our UEFI variable:
```
0B 0A 0C
```

## IFR

Let's look at the IFR code (`Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements/DEBUG/Form.lst`):
```
    orderedlist
>000000DC: 23 8F 14 00 15 00 07 00 01 00 21 00 00 03 00
      varid = FormData.OrderedListValue,
      prompt = STRING_TOKEN(0x0014),
      help = STRING_TOKEN(0x0015),
      option text = STRING_TOKEN(0x0016), value = 0x0A, flags = 0;
>000000EB: 09 07 16 00 00 00 0A
      option text = STRING_TOKEN(0x0017), value = 0x0B, flags = 0;
>000000F2: 09 07 17 00 00 00 0B
      option text = STRING_TOKEN(0x0018), value = 0x0C, flags = 0;
>000000F9: 09 07 18 00 00 00 0C
    endlist;
>00000100: 29 02
```

First code element is `EFI_IFR_ORDERED_LIST`:
```
EFI_IFR_ORDERED_LIST

Summary:
Creates a set question using an ordered list.

#define EFI_IFR_ORDERED_LIST_OP 0x23

typedef struct _EFI_IFR_ORDERED_LIST {
 EFI_IFR_OP_HEADER Header;
 EFI_IFR_QUESTION_HEADER Question;
 UINT8 MaxContainers;
 UINT8 Flags;
} EFI_IFR_ORDERED_LIST;

Members:
Header 		The byte sequence that defines the type of opcode as well as the length of the opcode being defined.
		Header.OpCode = EFI_IFR_ORDERED_LIST_OP.
Question 	The standard question header.
MaxContainers 	The maximum number of entries for which this tag will maintain an order.
		This value also identifies the size of the storage associated with this tag’s ordering array.
Flags		A bit-mask that determines which unique settings are active for this opcode.

Description:
Create an ordered list question in the current form. One thing to note is that valid values for the options
in ordered lists should never be a 0.
```

If you match data to the fields, you would get the following data for the new fields:
```
UINT8 MaxContainers;	// 0x03
UINT8 Flags;		// 0x00
```

Everything is in order, our element has 3 options, and therefore `MaxContainers=0x03`.

If you look at the options IFR code you could see that the options are encoded with the same opcode `EFI_IFR_ONE_OF_OPTION` that was used in the `oneof` element.

Here the principle is the same. If you encode our data as `UINT16` instead of `UINT8`
```
UINT16 OrderedListValue[3];
```
The compiler would encode options as `EFI_IFR_TYPE_NUM_SIZE_16` (=`UINT16`) and in the storage they would look as:
```
0B 00 0A 00 0C 00
```

With the `orderedlist` it is even possible to use non-numeric data types. For example you can encode variable as array of dates:
```
EFI_HII_DATE OrderedListValue[3];
```

For this off course you need to change the code in VFR:
```
orderedlist
  varid = FormData.OrderedListValue,
  prompt = STRING_TOKEN(ORDERED_LIST_PROMPT),
  help = STRING_TOKEN(ORDERED_LIST_HELP),
  option text = STRING_TOKEN(ORDERED_LIST_OPTION1), value = 2021/7/4, flags = 0;
  option text = STRING_TOKEN(ORDERED_LIST_OPTION2), value = 2022/8/5, flags = 0;
  option text = STRING_TOKEN(ORDERED_LIST_OPTION3), value = 2023/9/6, flags = 0;
endlist;
```

If you parse IFR data for such code, you could see that every option is encoded with `#define EFI_IFR_TYPE_DATE 0x06` type:
```
    orderedlist
>000000DC: 23 8F 14 00 15 00 07 00 01 00 21 00 00 0C 00
      varid = FormData.OrderedListValue,
      prompt = STRING_TOKEN(0x0014),
      help = STRING_TOKEN(0x0015),
      option text = STRING_TOKEN(0x0016), value = 2021/7/4, flags = 0;
>000000EB: 09 0A 16 00 06 06 E5 07 07 04
      option text = STRING_TOKEN(0x0017), value = 2022/8/5, flags = 0;
>000000F5: 09 0A 17 00 06 06 E6 07 08 05
      option text = STRING_TOKEN(0x0018), value = 2023/9/6, flags = 0;
>000000FF: 09 0A 18 00 06 06 E7 07 09 06
    endlist;
>00000109: 29 02
```

If the data array has a size lower than amount of available options, everything would compile, but in the HII, you would see only the first `array size` options. For example `UINT8 OrderedListValue[2]` would result to:

![Orderedlistr5](Orderedlist5.png?raw=true "Orderedlist5")