aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons_uncategorized/Lesson_Varstore_7/README.md
blob: 80f1ed5d4ac7430abb5e65cd6999125cf68a7723 (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
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.