]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c
Follow UEFI spec, set TimeOut and HwErrRecSupport variable by EFI variable service...
[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
d2b9b337 8Copyright (c) 2004 - 2013, 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
5676ccca 75\r
76/**\r
77 An empty function to pass error checking of CreateEventEx ().\r
78\r
79 @param Event Event whose notification function is being invoked.\r
80 @param Context Pointer to the notification function's context,\r
81 which is implementation-dependent.\r
82\r
83**/\r
84VOID\r
85EFIAPI\r
86BdsEmptyCallbackFunction (\r
87 IN EFI_EVENT Event,\r
88 IN VOID *Context\r
89 )\r
90{\r
91}\r
92\r
5c08e117 93/**\r
94\r
95 This function attempts to boot for the boot order specified\r
96 by platform policy.\r
97\r
98**/\r
99VOID\r
100BdsBootDeviceSelect (\r
101 VOID\r
102 )\r
103{\r
104 EFI_STATUS Status;\r
105 LIST_ENTRY *Link;\r
106 BDS_COMMON_OPTION *BootOption;\r
107 UINTN ExitDataSize;\r
108 CHAR16 *ExitData;\r
109 UINT16 Timeout;\r
110 LIST_ENTRY BootLists;\r
111 CHAR16 Buffer[20];\r
112 BOOLEAN BootNextExist;\r
113 LIST_ENTRY *LinkBootNext;\r
5676ccca 114 EFI_EVENT ConnectConInEvent;\r
5c08e117 115\r
116 //\r
117 // Got the latest boot option\r
118 //\r
119 BootNextExist = FALSE;\r
120 LinkBootNext = NULL;\r
5676ccca 121 ConnectConInEvent = NULL;\r
5c08e117 122 InitializeListHead (&BootLists);\r
123\r
124 //\r
125 // First check the boot next option\r
126 //\r
127 ZeroMem (Buffer, sizeof (Buffer));\r
128\r
5676ccca 129 //\r
130 // Create Event to signal ConIn connection request\r
131 //\r
132 if (PcdGetBool (PcdConInConnectOnDemand)) {\r
133 Status = gBS->CreateEventEx (\r
134 EVT_NOTIFY_SIGNAL,\r
135 TPL_CALLBACK,\r
136 BdsEmptyCallbackFunction,\r
137 NULL,\r
138 &gConnectConInEventGuid,\r
139 &ConnectConInEvent\r
140 );\r
141 if (EFI_ERROR(Status)) {\r
142 ConnectConInEvent = NULL;\r
143 }\r
144 }\r
145\r
5c08e117 146 if (mBootNext != NULL) {\r
147 //\r
148 // Indicate we have the boot next variable, so this time\r
149 // boot will always have this boot option\r
150 //\r
151 BootNextExist = TRUE;\r
152\r
153 //\r
154 // Clear the this variable so it's only exist in this time boot\r
155 //\r
156 gRT->SetVariable (\r
157 L"BootNext",\r
158 &gEfiGlobalVariableGuid,\r
159 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
160 0,\r
161 mBootNext\r
162 );\r
163\r
164 //\r
165 // Add the boot next boot option\r
166 //\r
167 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);\r
168 BootOption = BdsLibVariableToOption (&BootLists, Buffer);\r
128efbbc 169\r
5c08e117 170 //\r
171 // If fail to get boot option from variable, just return and do nothing.\r
172 //\r
173 if (BootOption == NULL) {\r
174 return;\r
175 }\r
128efbbc 176\r
5c08e117 177 BootOption->BootCurrent = *mBootNext;\r
178 }\r
179 //\r
180 // Parse the boot order to get boot option\r
181 //\r
182 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
d8600108
RN
183\r
184 //\r
185 // When we didn't have chance to build boot option variables in the first \r
186 // full configuration boot (e.g.: Reset in the first page or in Device Manager),\r
187 // we have no boot options in the following mini configuration boot.\r
188 // Give the last chance to enumerate the boot options.\r
189 //\r
190 if (IsListEmpty (&BootLists)) {\r
191 BdsLibEnumerateAllBootOption (&BootLists);\r
192 }\r
193\r
5c08e117 194 Link = BootLists.ForwardLink;\r
195\r
196 //\r
197 // Parameter check, make sure the loop will be valid\r
198 //\r
199 if (Link == NULL) {\r
200 return ;\r
201 }\r
202 //\r
203 // Here we make the boot in a loop, every boot success will\r
204 // return to the front page\r
205 //\r
206 for (;;) {\r
207 //\r
208 // Check the boot option list first\r
209 //\r
210 if (Link == &BootLists) {\r
5676ccca 211 //\r
212 // When LazyConIn enabled, signal connect ConIn event before enter UI\r
213 //\r
214 if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {\r
215 gBS->SignalEvent (ConnectConInEvent);\r
216 }\r
217\r
5c08e117 218 //\r
219 // There are two ways to enter here:\r
220 // 1. There is no active boot option, give user chance to\r
221 // add new boot option\r
222 // 2. All the active boot option processed, and there is no\r
223 // one is success to boot, then we back here to allow user\r
224 // add new active boot option\r
225 //\r
226 Timeout = 0xffff;\r
227 PlatformBdsEnterFrontPage (Timeout, FALSE);\r
228 InitializeListHead (&BootLists);\r
229 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
230 Link = BootLists.ForwardLink;\r
231 continue;\r
232 }\r
233 //\r
234 // Get the boot option from the link list\r
235 //\r
236 BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
237\r
238 //\r
239 // According to EFI Specification, if a load option is not marked\r
240 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically\r
241 // load the option.\r
242 //\r
243 if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {\r
244 //\r
baf46e70 245 // skip the header of the link list, because it has no boot option\r
5c08e117 246 //\r
247 Link = Link->ForwardLink;\r
248 continue;\r
249 }\r
250 //\r
251 // Make sure the boot option device path connected,\r
252 // but ignore the BBS device path\r
253 //\r
254 if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {\r
255 //\r
256 // Notes: the internal shell can not been connected with device path\r
257 // so we do not check the status here\r
258 //\r
259 BdsLibConnectDevicePath (BootOption->DevicePath);\r
260 }\r
2df686c6 261\r
262 //\r
263 // Restore to original mode before launching boot option.\r
264 //\r
265 BdsSetConsoleMode (FALSE);\r
266 \r
5c08e117 267 //\r
268 // All the driver options should have been processed since\r
269 // now boot will be performed.\r
270 //\r
271 Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
59b9d73e 272 if (Status != EFI_SUCCESS) {\r
5c08e117 273 //\r
274 // Call platform action to indicate the boot fail\r
275 //\r
276 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));\r
277 PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);\r
278\r
279 //\r
280 // Check the next boot option\r
281 //\r
282 Link = Link->ForwardLink;\r
283\r
284 } else {\r
285 //\r
286 // Call platform action to indicate the boot success\r
287 //\r
128efbbc 288 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));\r
5c08e117 289 PlatformBdsBootSuccess (BootOption);\r
290\r
291 //\r
292 // Boot success, then stop process the boot order, and\r
293 // present the boot manager menu, front page\r
294 //\r
5676ccca 295\r
296 //\r
297 // When LazyConIn enabled, signal connect ConIn Event before enter UI\r
298 //\r
299 if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {\r
300 gBS->SignalEvent (ConnectConInEvent);\r
301 }\r
302\r
5c08e117 303 Timeout = 0xffff;\r
304 PlatformBdsEnterFrontPage (Timeout, FALSE);\r
305\r
306 //\r
baf46e70 307 // Rescan the boot option list, avoid potential risk of the boot\r
5c08e117 308 // option change in front page\r
309 //\r
310 if (BootNextExist) {\r
311 LinkBootNext = BootLists.ForwardLink;\r
312 }\r
313\r
314 InitializeListHead (&BootLists);\r
315 if (LinkBootNext != NULL) {\r
316 //\r
317 // Reserve the boot next option\r
318 //\r
319 InsertTailList (&BootLists, LinkBootNext);\r
320 }\r
321\r
322 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
323 Link = BootLists.ForwardLink;\r
324 }\r
325 }\r
326\r
327}\r
328\r
7ea22852
ED
329/**\r
330\r
331 Validate input console variable data. \r
332\r
333 If found the device path is not a valid device path, remove the variable.\r
334 \r
335 @param VariableName Input console variable name.\r
336\r
337**/\r
7ea22852
ED
338VOID\r
339BdsFormalizeConsoleVariable (\r
340 IN CHAR16 *VariableName\r
341 )\r
342{\r
343 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
344 UINTN VariableSize;\r
345 EFI_STATUS Status;\r
346\r
347 DevicePath = BdsLibGetVariableAndSize (\r
348 VariableName,\r
349 &gEfiGlobalVariableGuid,\r
350 &VariableSize\r
351 );\r
98b241d6 352 if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) { \r
7ea22852
ED
353 Status = gRT->SetVariable (\r
354 VariableName,\r
355 &gEfiGlobalVariableGuid,\r
356 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
357 0,\r
358 NULL\r
359 );\r
360 ASSERT_EFI_ERROR (Status);\r
361 }\r
362}\r
363\r
364/**\r
365\r
18cf3950 366 Formalize Bds global variables. \r
7ea22852 367\r
18cf3950 368 1. For ConIn/ConOut/ConErr, if found the device path is not a valid device path, remove the variable.\r
369 2. For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps \r
370 3. Delete OsIndications variable if it is not NV/BS/RT UINT64\r
371 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.\r
372 \r
7ea22852
ED
373**/\r
374VOID \r
375BdsFormalizeEfiGlobalVariable (\r
376 VOID\r
377 )\r
378{\r
18cf3950 379 EFI_STATUS Status;\r
380 UINT64 OsIndicationSupport;\r
381 UINT64 OsIndication;\r
382 UINTN DataSize;\r
383 UINT32 Attributes;\r
384 \r
7ea22852
ED
385 //\r
386 // Validate Console variable.\r
387 //\r
388 BdsFormalizeConsoleVariable (L"ConIn");\r
389 BdsFormalizeConsoleVariable (L"ConOut");\r
390 BdsFormalizeConsoleVariable (L"ErrOut");\r
18cf3950 391\r
392 //\r
393 // OS indicater support variable\r
394 //\r
395 OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;\r
396 Status = gRT->SetVariable (\r
397 L"OsIndicationsSupported",\r
398 &gEfiGlobalVariableGuid,\r
399 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
400 sizeof(UINT64),\r
401 &OsIndicationSupport\r
402 );\r
403 ASSERT_EFI_ERROR (Status);\r
404\r
405 //\r
406 // If OsIndications is invalid, remove it.\r
407 // Invalid case\r
408 // 1. Data size != UINT64\r
409 // 2. OsIndication value inconsistence\r
410 // 3. OsIndication attribute inconsistence\r
411 //\r
412 OsIndication = 0;\r
413 Attributes = 0;\r
414 DataSize = sizeof(UINT64);\r
415 Status = gRT->GetVariable (\r
416 L"OsIndications",\r
417 &gEfiGlobalVariableGuid,\r
418 &Attributes,\r
419 &DataSize,\r
420 &OsIndication\r
421 );\r
422\r
423 if (!EFI_ERROR(Status)) {\r
424 if (DataSize != sizeof(UINT64) ||\r
425 (OsIndication & ~OsIndicationSupport) != 0 ||\r
426 Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE)){\r
427\r
428 DEBUG ((EFI_D_ERROR, "Unformalized OsIndications variable exists. Delete it\n"));\r
429 Status = gRT->SetVariable (\r
430 L"OsIndications",\r
431 &gEfiGlobalVariableGuid,\r
432 Attributes,\r
433 0,\r
434 &OsIndication\r
435 );\r
436 ASSERT_EFI_ERROR (Status);\r
437 }\r
438 }\r
439\r
7ea22852
ED
440}\r
441\r
5c08e117 442/**\r
443\r
444 Service routine for BdsInstance->Entry(). Devices are connected, the\r
445 consoles are initialized, and the boot options are tried.\r
446\r
447 @param This Protocol Instance structure.\r
448\r
449**/\r
450VOID\r
451EFIAPI\r
452BdsEntry (\r
453 IN EFI_BDS_ARCH_PROTOCOL *This\r
454 )\r
455{\r
5c08e117 456 LIST_ENTRY DriverOptionList;\r
457 LIST_ENTRY BootOptionList;\r
458 UINTN BootNextSize;\r
9a6b4de2 459 CHAR16 *FirmwareVendor;\r
e1e91b73
SZ
460 EFI_STATUS Status;\r
461 UINT16 BootTimeOut;\r
5c08e117 462\r
463 //\r
464 // Insert the performance probe\r
465 //\r
128efbbc 466 PERF_END (NULL, "DXE", NULL, 0);\r
467 PERF_START (NULL, "BDS", NULL, 0);\r
5c08e117 468\r
469 //\r
470 // Initialize the global system boot option and driver option\r
471 //\r
472 InitializeListHead (&DriverOptionList);\r
473 InitializeListHead (&BootOptionList);\r
474\r
475 //\r
476 // Initialize hotkey service\r
477 //\r
478 InitializeHotkeyService ();\r
479\r
9a6b4de2 480 //\r
481 // Fill in FirmwareVendor and FirmwareRevision from PCDs\r
482 //\r
483 FirmwareVendor = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor);\r
484 gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);\r
485 ASSERT (gST->FirmwareVendor != NULL);\r
486 gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);\r
487\r
488 //\r
489 // Fixup Tasble CRC after we updated Firmware Vendor and Revision\r
490 //\r
d2b9b337 491 gST->Hdr.CRC32 = 0;\r
9a6b4de2 492 gBS->CalculateCrc32 ((VOID *)gST, sizeof(EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);\r
493\r
7ea22852
ED
494 //\r
495 // Validate Variable.\r
496 //\r
497 BdsFormalizeEfiGlobalVariable();\r
498\r
cb38c322 499 //\r
500 // Report Status Code to indicate connecting drivers will happen\r
501 //\r
502 REPORT_STATUS_CODE (\r
503 EFI_PROGRESS_CODE,\r
504 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)\r
505 );\r
506\r
5c08e117 507 //\r
508 // Do the platform init, can be customized by OEM/IBV\r
509 //\r
128efbbc 510 PERF_START (NULL, "PlatformBds", "BDS", 0);\r
f7cdf5cd 511 PlatformBdsInit ();\r
5c08e117 512\r
a2b35995 513 InitializeHwErrRecSupport();\r
128efbbc 514\r
e1e91b73
SZ
515 //\r
516 // Initialize L"Timeout" EFI global variable.\r
517 //\r
518 BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);\r
519 if (BootTimeOut != 0xFFFF) {\r
520 //\r
521 // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification\r
522 // define same behavior between no value or 0xFFFF value for L"Timeout".\r
523 //\r
524 Status = gRT->SetVariable (\r
525 L"Timeout",\r
526 &gEfiGlobalVariableGuid,\r
527 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
528 sizeof (UINT16),\r
529 &BootTimeOut\r
530 );\r
531 ASSERT_EFI_ERROR(Status);\r
532 }\r
533\r
5c08e117 534 //\r
535 // bugbug: platform specific code\r
536 // Initialize the platform specific string and language\r
537 //\r
538 InitializeStringSupport ();\r
539 InitializeLanguage (TRUE);\r
540 InitializeFrontPage (TRUE);\r
541\r
542 //\r
543 // Set up the device list based on EFI 1.1 variables\r
544 // process Driver#### and Load the driver's in the\r
545 // driver option list\r
546 //\r
547 BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");\r
548 if (!IsListEmpty (&DriverOptionList)) {\r
549 BdsLibLoadDrivers (&DriverOptionList);\r
550 }\r
551 //\r
552 // Check if we have the boot next option\r
553 //\r
554 mBootNext = BdsLibGetVariableAndSize (\r
555 L"BootNext",\r
556 &gEfiGlobalVariableGuid,\r
557 &BootNextSize\r
558 );\r
559\r
560 //\r
561 // Setup some platform policy here\r
562 //\r
19bf20e1 563 PlatformBdsPolicyBehavior (&DriverOptionList, &BootOptionList, BdsProcessCapsules, BdsMemoryTest);\r
128efbbc 564 PERF_END (NULL, "PlatformBds", "BDS", 0);\r
5c08e117 565\r
566 //\r
567 // BDS select the boot device to load OS\r
568 //\r
569 BdsBootDeviceSelect ();\r
570\r
571 //\r
572 // Only assert here since this is the right behavior, we should never\r
573 // return back to DxeCore.\r
574 //\r
575 ASSERT (FALSE);\r
576\r
577 return ;\r
578}\r