]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c
Add 2 new Bds features
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / BdsDxe / BdsEntry.c
CommitLineData
5c08e117 1/** @file\r
128efbbc 2 This module produce main entry for BDS phase - BdsEntry.\r
5c08e117 3 When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed\r
4 which contains interface of BdsEntry.\r
5 After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked\r
6 to enter BDS phase.\r
7\r
2df686c6 8Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
180a5a35 9This program and the accompanying materials\r
5c08e117 10are licensed and made available under the terms and conditions of the BSD License\r
11which accompanies this distribution. The full text of the license may be found at\r
12http://opensource.org/licenses/bsd-license.php\r
13\r
14THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16\r
17**/\r
18\r
19#include "Bds.h"\r
20#include "Language.h"\r
21#include "FrontPage.h"\r
22#include "Hotkey.h"\r
23#include "HwErrRecSupport.h"\r
24\r
25///\r
26/// BDS arch protocol instance initial value.\r
27///\r
28/// Note: Current BDS not directly get the BootMode, DefaultBoot,\r
29/// TimeoutDefault, MemoryTestLevel value from the BDS arch protocol.\r
128efbbc 30/// Please refer to the library useage of BdsLibGetBootMode, BdsLibGetTimeout\r
5c08e117 31/// and PlatformBdsDiagnostics in BdsPlatform.c\r
32///\r
f7cdf5cd 33EFI_HANDLE gBdsHandle = NULL;\r
34\r
35EFI_BDS_ARCH_PROTOCOL gBds = {\r
36 BdsEntry\r
5c08e117 37};\r
38\r
39UINT16 *mBootNext = NULL;\r
40\r
5c08e117 41/**\r
42\r
43 Install Boot Device Selection Protocol\r
44\r
45 @param ImageHandle The image handle.\r
46 @param SystemTable The system table.\r
47\r
48 @retval EFI_SUCEESS BDS has finished initializing.\r
49 Return the dispatcher and recall BDS.Entry\r
50 @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface\r
51\r
52**/\r
53EFI_STATUS\r
54EFIAPI\r
55BdsInitialize (\r
56 IN EFI_HANDLE ImageHandle,\r
57 IN EFI_SYSTEM_TABLE *SystemTable\r
58 )\r
59{\r
60 EFI_STATUS Status;\r
61\r
5c08e117 62 //\r
63 // Install protocol interface\r
64 //\r
f7cdf5cd 65 Status = gBS->InstallMultipleProtocolInterfaces (\r
66 &gBdsHandle,\r
67 &gEfiBdsArchProtocolGuid, &gBds,\r
68 NULL\r
5c08e117 69 );\r
70 ASSERT_EFI_ERROR (Status);\r
71\r
72 return Status;\r
73}\r
74\r
75/**\r
76\r
77 This function attempts to boot for the boot order specified\r
78 by platform policy.\r
79\r
80**/\r
81VOID\r
82BdsBootDeviceSelect (\r
83 VOID\r
84 )\r
85{\r
86 EFI_STATUS Status;\r
87 LIST_ENTRY *Link;\r
88 BDS_COMMON_OPTION *BootOption;\r
89 UINTN ExitDataSize;\r
90 CHAR16 *ExitData;\r
91 UINT16 Timeout;\r
92 LIST_ENTRY BootLists;\r
93 CHAR16 Buffer[20];\r
94 BOOLEAN BootNextExist;\r
95 LIST_ENTRY *LinkBootNext;\r
96\r
97 //\r
98 // Got the latest boot option\r
99 //\r
100 BootNextExist = FALSE;\r
101 LinkBootNext = NULL;\r
102 InitializeListHead (&BootLists);\r
103\r
104 //\r
105 // First check the boot next option\r
106 //\r
107 ZeroMem (Buffer, sizeof (Buffer));\r
108\r
109 if (mBootNext != NULL) {\r
110 //\r
111 // Indicate we have the boot next variable, so this time\r
112 // boot will always have this boot option\r
113 //\r
114 BootNextExist = TRUE;\r
115\r
116 //\r
117 // Clear the this variable so it's only exist in this time boot\r
118 //\r
119 gRT->SetVariable (\r
120 L"BootNext",\r
121 &gEfiGlobalVariableGuid,\r
122 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
123 0,\r
124 mBootNext\r
125 );\r
126\r
127 //\r
128 // Add the boot next boot option\r
129 //\r
130 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);\r
131 BootOption = BdsLibVariableToOption (&BootLists, Buffer);\r
128efbbc 132\r
5c08e117 133 //\r
134 // If fail to get boot option from variable, just return and do nothing.\r
135 //\r
136 if (BootOption == NULL) {\r
137 return;\r
138 }\r
128efbbc 139\r
5c08e117 140 BootOption->BootCurrent = *mBootNext;\r
141 }\r
142 //\r
143 // Parse the boot order to get boot option\r
144 //\r
145 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
d8600108
RN
146\r
147 //\r
148 // When we didn't have chance to build boot option variables in the first \r
149 // full configuration boot (e.g.: Reset in the first page or in Device Manager),\r
150 // we have no boot options in the following mini configuration boot.\r
151 // Give the last chance to enumerate the boot options.\r
152 //\r
153 if (IsListEmpty (&BootLists)) {\r
154 BdsLibEnumerateAllBootOption (&BootLists);\r
155 }\r
156\r
5c08e117 157 Link = BootLists.ForwardLink;\r
158\r
159 //\r
160 // Parameter check, make sure the loop will be valid\r
161 //\r
162 if (Link == NULL) {\r
163 return ;\r
164 }\r
165 //\r
166 // Here we make the boot in a loop, every boot success will\r
167 // return to the front page\r
168 //\r
169 for (;;) {\r
170 //\r
171 // Check the boot option list first\r
172 //\r
173 if (Link == &BootLists) {\r
174 //\r
175 // There are two ways to enter here:\r
176 // 1. There is no active boot option, give user chance to\r
177 // add new boot option\r
178 // 2. All the active boot option processed, and there is no\r
179 // one is success to boot, then we back here to allow user\r
180 // add new active boot option\r
181 //\r
182 Timeout = 0xffff;\r
183 PlatformBdsEnterFrontPage (Timeout, FALSE);\r
184 InitializeListHead (&BootLists);\r
185 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
186 Link = BootLists.ForwardLink;\r
187 continue;\r
188 }\r
189 //\r
190 // Get the boot option from the link list\r
191 //\r
192 BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
193\r
194 //\r
195 // According to EFI Specification, if a load option is not marked\r
196 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically\r
197 // load the option.\r
198 //\r
199 if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {\r
200 //\r
baf46e70 201 // skip the header of the link list, because it has no boot option\r
5c08e117 202 //\r
203 Link = Link->ForwardLink;\r
204 continue;\r
205 }\r
206 //\r
207 // Make sure the boot option device path connected,\r
208 // but ignore the BBS device path\r
209 //\r
210 if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {\r
211 //\r
212 // Notes: the internal shell can not been connected with device path\r
213 // so we do not check the status here\r
214 //\r
215 BdsLibConnectDevicePath (BootOption->DevicePath);\r
216 }\r
2df686c6 217\r
218 //\r
219 // Restore to original mode before launching boot option.\r
220 //\r
221 BdsSetConsoleMode (FALSE);\r
222 \r
5c08e117 223 //\r
224 // All the driver options should have been processed since\r
225 // now boot will be performed.\r
226 //\r
227 Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
59b9d73e 228 if (Status != EFI_SUCCESS) {\r
5c08e117 229 //\r
230 // Call platform action to indicate the boot fail\r
231 //\r
232 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));\r
233 PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);\r
234\r
235 //\r
236 // Check the next boot option\r
237 //\r
238 Link = Link->ForwardLink;\r
239\r
240 } else {\r
241 //\r
242 // Call platform action to indicate the boot success\r
243 //\r
128efbbc 244 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));\r
5c08e117 245 PlatformBdsBootSuccess (BootOption);\r
246\r
247 //\r
248 // Boot success, then stop process the boot order, and\r
249 // present the boot manager menu, front page\r
250 //\r
251 Timeout = 0xffff;\r
252 PlatformBdsEnterFrontPage (Timeout, FALSE);\r
253\r
254 //\r
baf46e70 255 // Rescan the boot option list, avoid potential risk of the boot\r
5c08e117 256 // option change in front page\r
257 //\r
258 if (BootNextExist) {\r
259 LinkBootNext = BootLists.ForwardLink;\r
260 }\r
261\r
262 InitializeListHead (&BootLists);\r
263 if (LinkBootNext != NULL) {\r
264 //\r
265 // Reserve the boot next option\r
266 //\r
267 InsertTailList (&BootLists, LinkBootNext);\r
268 }\r
269\r
270 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
271 Link = BootLists.ForwardLink;\r
272 }\r
273 }\r
274\r
275}\r
276\r
7ea22852
ED
277/**\r
278 Validate the device path instance. \r
279\r
280 Only base on the length filed in the device path node to validate the device path. \r
281\r
282 @param DevicePath A pointer to a device path data structure.\r
283 @param MaxSize Max valid device path size. If big than this size, \r
284 return error.\r
285 \r
286 @retval TRUE An valid device path.\r
287 @retval FALSE An invalid device path.\r
288\r
289**/\r
290BOOLEAN\r
291IsValidDevicePath (\r
292 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
293 IN UINTN MaxSize\r
294 )\r
295{\r
296 UINTN Size;\r
297 UINTN NodeSize;\r
298\r
299 if (DevicePath == NULL) {\r
300 return TRUE;\r
301 }\r
302\r
303 Size = 0;\r
304\r
305 while (!IsDevicePathEnd (DevicePath)) {\r
306 NodeSize = DevicePathNodeLength (DevicePath);\r
307 if (NodeSize < END_DEVICE_PATH_LENGTH) {\r
308 return FALSE;\r
309 }\r
310\r
311 Size += NodeSize;\r
312 if (Size > MaxSize) {\r
313 return FALSE;\r
314 }\r
315\r
316 DevicePath = NextDevicePathNode (DevicePath);\r
317 }\r
318\r
319 Size += DevicePathNodeLength (DevicePath);\r
320 if (Size > MaxSize) {\r
321 return FALSE;\r
322 }\r
323\r
324 return TRUE;\r
325}\r
326\r
327/**\r
328\r
329 Validate input console variable data. \r
330\r
331 If found the device path is not a valid device path, remove the variable.\r
332 \r
333 @param VariableName Input console variable name.\r
334\r
335**/\r
7ea22852
ED
336VOID\r
337BdsFormalizeConsoleVariable (\r
338 IN CHAR16 *VariableName\r
339 )\r
340{\r
341 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
342 UINTN VariableSize;\r
343 EFI_STATUS Status;\r
344\r
345 DevicePath = BdsLibGetVariableAndSize (\r
346 VariableName,\r
347 &gEfiGlobalVariableGuid,\r
348 &VariableSize\r
349 );\r
350 if (!IsValidDevicePath (DevicePath, VariableSize)) { \r
351 Status = gRT->SetVariable (\r
352 VariableName,\r
353 &gEfiGlobalVariableGuid,\r
354 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
355 0,\r
356 NULL\r
357 );\r
358 ASSERT_EFI_ERROR (Status);\r
359 }\r
360}\r
361\r
362/**\r
363\r
18cf3950 364 Formalize Bds global variables. \r
7ea22852 365\r
18cf3950 366 1. For ConIn/ConOut/ConErr, if found the device path is not a valid device path, remove the variable.\r
367 2. For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps \r
368 3. Delete OsIndications variable if it is not NV/BS/RT UINT64\r
369 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.\r
370 \r
7ea22852
ED
371**/\r
372VOID \r
373BdsFormalizeEfiGlobalVariable (\r
374 VOID\r
375 )\r
376{\r
18cf3950 377 EFI_STATUS Status;\r
378 UINT64 OsIndicationSupport;\r
379 UINT64 OsIndication;\r
380 UINTN DataSize;\r
381 UINT32 Attributes;\r
382 \r
7ea22852
ED
383 //\r
384 // Validate Console variable.\r
385 //\r
386 BdsFormalizeConsoleVariable (L"ConIn");\r
387 BdsFormalizeConsoleVariable (L"ConOut");\r
388 BdsFormalizeConsoleVariable (L"ErrOut");\r
18cf3950 389\r
390 //\r
391 // OS indicater support variable\r
392 //\r
393 OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;\r
394 Status = gRT->SetVariable (\r
395 L"OsIndicationsSupported",\r
396 &gEfiGlobalVariableGuid,\r
397 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
398 sizeof(UINT64),\r
399 &OsIndicationSupport\r
400 );\r
401 ASSERT_EFI_ERROR (Status);\r
402\r
403 //\r
404 // If OsIndications is invalid, remove it.\r
405 // Invalid case\r
406 // 1. Data size != UINT64\r
407 // 2. OsIndication value inconsistence\r
408 // 3. OsIndication attribute inconsistence\r
409 //\r
410 OsIndication = 0;\r
411 Attributes = 0;\r
412 DataSize = sizeof(UINT64);\r
413 Status = gRT->GetVariable (\r
414 L"OsIndications",\r
415 &gEfiGlobalVariableGuid,\r
416 &Attributes,\r
417 &DataSize,\r
418 &OsIndication\r
419 );\r
420\r
421 if (!EFI_ERROR(Status)) {\r
422 if (DataSize != sizeof(UINT64) ||\r
423 (OsIndication & ~OsIndicationSupport) != 0 ||\r
424 Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE)){\r
425\r
426 DEBUG ((EFI_D_ERROR, "Unformalized OsIndications variable exists. Delete it\n"));\r
427 Status = gRT->SetVariable (\r
428 L"OsIndications",\r
429 &gEfiGlobalVariableGuid,\r
430 Attributes,\r
431 0,\r
432 &OsIndication\r
433 );\r
434 ASSERT_EFI_ERROR (Status);\r
435 }\r
436 }\r
437\r
7ea22852
ED
438}\r
439\r
5c08e117 440/**\r
441\r
442 Service routine for BdsInstance->Entry(). Devices are connected, the\r
443 consoles are initialized, and the boot options are tried.\r
444\r
445 @param This Protocol Instance structure.\r
446\r
447**/\r
448VOID\r
449EFIAPI\r
450BdsEntry (\r
451 IN EFI_BDS_ARCH_PROTOCOL *This\r
452 )\r
453{\r
5c08e117 454 LIST_ENTRY DriverOptionList;\r
455 LIST_ENTRY BootOptionList;\r
456 UINTN BootNextSize;\r
9a6b4de2 457 CHAR16 *FirmwareVendor;\r
5c08e117 458\r
459 //\r
460 // Insert the performance probe\r
461 //\r
128efbbc 462 PERF_END (NULL, "DXE", NULL, 0);\r
463 PERF_START (NULL, "BDS", NULL, 0);\r
5c08e117 464\r
465 //\r
466 // Initialize the global system boot option and driver option\r
467 //\r
468 InitializeListHead (&DriverOptionList);\r
469 InitializeListHead (&BootOptionList);\r
470\r
471 //\r
472 // Initialize hotkey service\r
473 //\r
474 InitializeHotkeyService ();\r
475\r
9a6b4de2 476 //\r
477 // Fill in FirmwareVendor and FirmwareRevision from PCDs\r
478 //\r
479 FirmwareVendor = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor);\r
480 gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);\r
481 ASSERT (gST->FirmwareVendor != NULL);\r
482 gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);\r
483\r
484 //\r
485 // Fixup Tasble CRC after we updated Firmware Vendor and Revision\r
486 //\r
487 gBS->CalculateCrc32 ((VOID *)gST, sizeof(EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);\r
488\r
7ea22852
ED
489 //\r
490 // Validate Variable.\r
491 //\r
492 BdsFormalizeEfiGlobalVariable();\r
493\r
5c08e117 494 //\r
495 // Do the platform init, can be customized by OEM/IBV\r
496 //\r
128efbbc 497 PERF_START (NULL, "PlatformBds", "BDS", 0);\r
f7cdf5cd 498 PlatformBdsInit ();\r
5c08e117 499\r
a2b35995 500 InitializeHwErrRecSupport();\r
128efbbc 501\r
5c08e117 502 //\r
503 // bugbug: platform specific code\r
504 // Initialize the platform specific string and language\r
505 //\r
506 InitializeStringSupport ();\r
507 InitializeLanguage (TRUE);\r
508 InitializeFrontPage (TRUE);\r
509\r
510 //\r
511 // Set up the device list based on EFI 1.1 variables\r
512 // process Driver#### and Load the driver's in the\r
513 // driver option list\r
514 //\r
515 BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");\r
516 if (!IsListEmpty (&DriverOptionList)) {\r
517 BdsLibLoadDrivers (&DriverOptionList);\r
518 }\r
519 //\r
520 // Check if we have the boot next option\r
521 //\r
522 mBootNext = BdsLibGetVariableAndSize (\r
523 L"BootNext",\r
524 &gEfiGlobalVariableGuid,\r
525 &BootNextSize\r
526 );\r
527\r
528 //\r
529 // Setup some platform policy here\r
530 //\r
19bf20e1 531 PlatformBdsPolicyBehavior (&DriverOptionList, &BootOptionList, BdsProcessCapsules, BdsMemoryTest);\r
128efbbc 532 PERF_END (NULL, "PlatformBds", "BDS", 0);\r
5c08e117 533\r
534 //\r
535 // BDS select the boot device to load OS\r
536 //\r
537 BdsBootDeviceSelect ();\r
538\r
539 //\r
540 // Only assert here since this is the right behavior, we should never\r
541 // return back to DxeCore.\r
542 //\r
543 ASSERT (FALSE);\r
544\r
545 return ;\r
546}\r