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