1 /** @file
2 The platform boot manager reference implementation
3
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "BootManager.h"
10
11 UINT16 mKeyInput;
12 LIST_ENTRY mBootOptionsList;
13 BDS_COMMON_OPTION *gOption;
14 CHAR16 *mDeviceTypeStr[] = {
15 L"Legacy BEV",
16 L"Legacy Floppy",
17 L"Legacy Hard Drive",
18 L"Legacy CD ROM",
19 L"Legacy PCMCIA",
20 L"Legacy USB",
21 L"Legacy Embedded Network",
22 L"Legacy Unknown Device"
23 };
24
25
26 HII_VENDOR_DEVICE_PATH mBootManagerHiiVendorDevicePath = {
27 {
28 {
29 HARDWARE_DEVICE_PATH,
30 HW_VENDOR_DP,
31 {
32 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
33 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
34 }
35 },
36 BOOT_MANAGER_FORMSET_GUID
37 },
38 {
39 END_DEVICE_PATH_TYPE,
40 END_ENTIRE_DEVICE_PATH_SUBTYPE,
41 {
42 (UINT8) (END_DEVICE_PATH_LENGTH),
43 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
44 }
45 }
46 };
47
48 BOOT_MANAGER_CALLBACK_DATA gBootManagerPrivate = {
49 BOOT_MANAGER_CALLBACK_DATA_SIGNATURE,
50 NULL,
51 NULL,
52 {
53 FakeExtractConfig,
54 FakeRouteConfig,
55 BootManagerCallback
56 }
57 };
58
59 /**
60 This call back function is registered with Boot Manager formset.
61 When user selects a boot option, this call back function will
62 be triggered. The boot option is saved for later processing.
63
64
65 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
66 @param Action Specifies the type of action taken by the browser.
67 @param QuestionId A unique value which is sent to the original exporting driver
68 so that it can identify the type of data to expect.
69 @param Type The type of value for the question.
70 @param Value A pointer to the data being sent to the original exporting driver.
71 @param ActionRequest On return, points to the action requested by the callback function.
72
73 @retval EFI_SUCCESS The callback successfully handled the action.
74 @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
75
76 **/
77 EFI_STATUS
78 EFIAPI
BootManagerCallback(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN EFI_BROWSER_ACTION Action,IN EFI_QUESTION_ID QuestionId,IN UINT8 Type,IN EFI_IFR_TYPE_VALUE * Value,OUT EFI_BROWSER_ACTION_REQUEST * ActionRequest)79 BootManagerCallback (
80 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
81 IN EFI_BROWSER_ACTION Action,
82 IN EFI_QUESTION_ID QuestionId,
83 IN UINT8 Type,
84 IN EFI_IFR_TYPE_VALUE *Value,
85 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
86 )
87 {
88 BDS_COMMON_OPTION *Option;
89 LIST_ENTRY *Link;
90 UINT16 KeyCount;
91
92 if (Action == EFI_BROWSER_ACTION_CHANGED) {
93 if ((Value == NULL) || (ActionRequest == NULL)) {
94 return EFI_INVALID_PARAMETER;
95 }
96
97 //
98 // Initialize the key count
99 //
100 KeyCount = 0;
101
102 for (Link = GetFirstNode (&mBootOptionsList); !IsNull (&mBootOptionsList, Link); Link = GetNextNode (&mBootOptionsList, Link)) {
103 Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
104
105 KeyCount++;
106
107 gOption = Option;
108
109 //
110 // Is this device the one chosen?
111 //
112 if (KeyCount == QuestionId) {
113 //
114 // Assigning the returned Key to a global allows the original routine to know what was chosen
115 //
116 mKeyInput = QuestionId;
117
118 //
119 // Request to exit SendForm(), so that we could boot the selected option
120 //
121 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
122 break;
123 }
124 }
125
126 return EFI_SUCCESS;
127 }
128
129 //
130 // All other action return unsupported.
131 //
132 return EFI_UNSUPPORTED;
133 }
134
135 /**
136
137 Registers HII packages for the Boot Manger to HII Database.
138 It also registers the browser call back function.
139
140 @retval EFI_SUCCESS HII packages for the Boot Manager were registered successfully.
141 @retval EFI_OUT_OF_RESOURCES HII packages for the Boot Manager failed to be registered.
142
143 **/
144 EFI_STATUS
InitializeBootManager(VOID)145 InitializeBootManager (
146 VOID
147 )
148 {
149 EFI_STATUS Status;
150
151 //
152 // Install Device Path Protocol and Config Access protocol to driver handle
153 //
154 Status = gBS->InstallMultipleProtocolInterfaces (
155 &gBootManagerPrivate.DriverHandle,
156 &gEfiDevicePathProtocolGuid,
157 &mBootManagerHiiVendorDevicePath,
158 &gEfiHiiConfigAccessProtocolGuid,
159 &gBootManagerPrivate.ConfigAccess,
160 NULL
161 );
162 ASSERT_EFI_ERROR (Status);
163
164 //
165 // Publish our HII data
166 //
167 gBootManagerPrivate.HiiHandle = HiiAddPackages (
168 &gBootManagerFormSetGuid,
169 gBootManagerPrivate.DriverHandle,
170 BootManagerVfrBin,
171 BdsDxeStrings,
172 NULL
173 );
174 if (gBootManagerPrivate.HiiHandle == NULL) {
175 Status = EFI_OUT_OF_RESOURCES;
176 } else {
177 Status = EFI_SUCCESS;
178 }
179 return Status;
180 }
181
182 /**
183 This function invokes Boot Manager. If all devices have not a chance to be connected,
184 the connect all will be triggered. It then enumerate all boot options. If
185 a boot option from the Boot Manager page is selected, Boot Manager will boot
186 from this boot option.
187
188 **/
189 VOID
CallBootManager(VOID)190 CallBootManager (
191 VOID
192 )
193 {
194 EFI_STATUS Status;
195 BDS_COMMON_OPTION *Option;
196 LIST_ENTRY *Link;
197 CHAR16 *ExitData;
198 UINTN ExitDataSize;
199 EFI_STRING_ID Token;
200 EFI_INPUT_KEY Key;
201 CHAR16 *HelpString;
202 UINTN HelpSize;
203 EFI_STRING_ID HelpToken;
204 UINT16 *TempStr;
205 EFI_HII_HANDLE HiiHandle;
206 EFI_BROWSER_ACTION_REQUEST ActionRequest;
207 VOID *StartOpCodeHandle;
208 VOID *EndOpCodeHandle;
209 EFI_IFR_GUID_LABEL *StartLabel;
210 EFI_IFR_GUID_LABEL *EndLabel;
211 UINT16 DeviceType;
212 BOOLEAN IsLegacyOption;
213 BOOLEAN NeedEndOp;
214
215 DeviceType = (UINT16) -1;
216 gOption = NULL;
217 InitializeListHead (&mBootOptionsList);
218
219 //
220 // Connect all prior to entering the platform setup menu.
221 //
222 if (!gConnectAllHappened) {
223 BdsLibConnectAllDriversToAllControllers ();
224 gConnectAllHappened = TRUE;
225 }
226
227 BdsLibEnumerateAllBootOption (&mBootOptionsList);
228
229 //
230 // Group the legacy boot options for the same device type
231 //
232 GroupMultipleLegacyBootOption4SameType ();
233
234 InitializeListHead (&mBootOptionsList);
235 BdsLibBuildOptionFromVar (&mBootOptionsList, L"BootOrder");
236
237 HiiHandle = gBootManagerPrivate.HiiHandle;
238
239 //
240 // Allocate space for creation of UpdateData Buffer
241 //
242 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
243 ASSERT (StartOpCodeHandle != NULL);
244
245 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
246 ASSERT (EndOpCodeHandle != NULL);
247
248 //
249 // Create Hii Extend Label OpCode as the start opcode
250 //
251 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
252 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
253 StartLabel->Number = LABEL_BOOT_OPTION;
254
255 //
256 // Create Hii Extend Label OpCode as the end opcode
257 //
258 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
259 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
260 EndLabel->Number = LABEL_BOOT_OPTION_END;
261
262 mKeyInput = 0;
263 NeedEndOp = FALSE;
264 for (Link = GetFirstNode (&mBootOptionsList); !IsNull (&mBootOptionsList, Link); Link = GetNextNode (&mBootOptionsList, Link)) {
265 Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
266
267 //
268 // At this stage we are creating a menu entry, thus the Keys are reproduceable
269 //
270 mKeyInput++;
271
272 //
273 // Don't display the hidden/inactive boot option
274 //
275 if (((Option->Attribute & LOAD_OPTION_HIDDEN) != 0) || ((Option->Attribute & LOAD_OPTION_ACTIVE) == 0)) {
276 continue;
277 }
278
279 //
280 // Group the legacy boot option in the sub title created dynamically
281 //
282 IsLegacyOption = (BOOLEAN) (
283 (DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
284 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
285 );
286
287 if (!IsLegacyOption && NeedEndOp) {
288 NeedEndOp = FALSE;
289 HiiCreateEndOpCode (StartOpCodeHandle);
290 }
291
292 if (IsLegacyOption && DeviceType != ((BBS_BBS_DEVICE_PATH *) Option->DevicePath)->DeviceType) {
293 if (NeedEndOp) {
294 HiiCreateEndOpCode (StartOpCodeHandle);
295 }
296
297 DeviceType = ((BBS_BBS_DEVICE_PATH *) Option->DevicePath)->DeviceType;
298 Token = HiiSetString (
299 HiiHandle,
300 0,
301 mDeviceTypeStr[
302 MIN (DeviceType & 0xF, ARRAY_SIZE (mDeviceTypeStr) - 1)
303 ],
304 NULL
305 );
306 HiiCreateSubTitleOpCode (StartOpCodeHandle, Token, 0, 0, 1);
307 NeedEndOp = TRUE;
308 }
309
310 ASSERT (Option->Description != NULL);
311
312 Token = HiiSetString (HiiHandle, 0, Option->Description, NULL);
313
314 TempStr = DevicePathToStr (Option->DevicePath);
315 HelpSize = StrSize (TempStr) + StrSize (L"Device Path : ");
316 HelpString = AllocateZeroPool (HelpSize);
317 ASSERT (HelpString != NULL);
318 StrCatS (HelpString, HelpSize / sizeof (CHAR16), L"Device Path : ");
319 StrCatS (HelpString, HelpSize / sizeof (CHAR16), TempStr);
320
321 HelpToken = HiiSetString (HiiHandle, 0, HelpString, NULL);
322
323 HiiCreateActionOpCode (
324 StartOpCodeHandle,
325 mKeyInput,
326 Token,
327 HelpToken,
328 EFI_IFR_FLAG_CALLBACK,
329 0
330 );
331 }
332
333 if (NeedEndOp) {
334 HiiCreateEndOpCode (StartOpCodeHandle);
335 }
336
337 HiiUpdateForm (
338 HiiHandle,
339 &gBootManagerFormSetGuid,
340 BOOT_MANAGER_FORM_ID,
341 StartOpCodeHandle,
342 EndOpCodeHandle
343 );
344
345 HiiFreeOpCodeHandle (StartOpCodeHandle);
346 HiiFreeOpCodeHandle (EndOpCodeHandle);
347
348 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
349 Status = gFormBrowser2->SendForm (
350 gFormBrowser2,
351 &HiiHandle,
352 1,
353 &gBootManagerFormSetGuid,
354 0,
355 NULL,
356 &ActionRequest
357 );
358 if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
359 EnableResetRequired ();
360 }
361
362 if (gOption == NULL) {
363 return ;
364 }
365
366 //
367 // Will leave browser, check any reset required change is applied? if yes, reset system
368 //
369 SetupResetReminder ();
370
371 //
372 // Restore to original mode before launching boot option.
373 //
374 BdsSetConsoleMode (FALSE);
375
376 //
377 // parse the selected option
378 //
379 Status = BdsLibBootViaBootOption (gOption, gOption->DevicePath, &ExitDataSize, &ExitData);
380
381 if (!EFI_ERROR (Status)) {
382 gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
383 PlatformBdsBootSuccess (gOption);
384 } else {
385 gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
386 PlatformBdsBootFail (gOption, Status, ExitData, ExitDataSize);
387 gST->ConOut->OutputString (
388 gST->ConOut,
389 GetStringById (STRING_TOKEN (STR_ANY_KEY_CONTINUE))
390 );
391 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
392 }
393 }
394