2 This module produce main entry for BDS phase - BdsEntry.
3 When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed
4 which contains interface of BdsEntry.
5 After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked
8 Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 #include "FrontPage.h"
23 #include "HwErrRecSupport.h"
26 /// BDS arch protocol instance initial value.
28 /// Note: Current BDS not directly get the BootMode, DefaultBoot,
29 /// TimeoutDefault, MemoryTestLevel value from the BDS arch protocol.
30 /// Please refer to the library useage of BdsLibGetBootMode, BdsLibGetTimeout
31 /// and PlatformBdsDiagnostics in BdsPlatform.c
33 EFI_HANDLE gBdsHandle
= NULL
;
35 EFI_BDS_ARCH_PROTOCOL gBds
= {
39 UINT16
*mBootNext
= NULL
;
43 Install Boot Device Selection Protocol
45 @param ImageHandle The image handle.
46 @param SystemTable The system table.
48 @retval EFI_SUCEESS BDS has finished initializing.
49 Return the dispatcher and recall BDS.Entry
50 @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface
56 IN EFI_HANDLE ImageHandle
,
57 IN EFI_SYSTEM_TABLE
*SystemTable
63 // Install protocol interface
65 Status
= gBS
->InstallMultipleProtocolInterfaces (
67 &gEfiBdsArchProtocolGuid
, &gBds
,
70 ASSERT_EFI_ERROR (Status
);
77 An empty function to pass error checking of CreateEventEx ().
79 @param Event Event whose notification function is being invoked.
80 @param Context Pointer to the notification function's context,
81 which is implementation-dependent.
86 BdsEmptyCallbackFunction (
95 This function attempts to boot for the boot order specified
100 BdsBootDeviceSelect (
106 BDS_COMMON_OPTION
*BootOption
;
110 LIST_ENTRY BootLists
;
112 BOOLEAN BootNextExist
;
113 LIST_ENTRY
*LinkBootNext
;
114 EFI_EVENT ConnectConInEvent
;
117 // Got the latest boot option
119 BootNextExist
= FALSE
;
121 ConnectConInEvent
= NULL
;
122 InitializeListHead (&BootLists
);
125 // First check the boot next option
127 ZeroMem (Buffer
, sizeof (Buffer
));
130 // Create Event to signal ConIn connection request
132 if (PcdGetBool (PcdConInConnectOnDemand
)) {
133 Status
= gBS
->CreateEventEx (
136 BdsEmptyCallbackFunction
,
138 &gConnectConInEventGuid
,
141 if (EFI_ERROR(Status
)) {
142 ConnectConInEvent
= NULL
;
146 if (mBootNext
!= NULL
) {
148 // Indicate we have the boot next variable, so this time
149 // boot will always have this boot option
151 BootNextExist
= TRUE
;
154 // Clear the this variable so it's only exist in this time boot
158 &gEfiGlobalVariableGuid
,
159 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
165 // Add the boot next boot option
167 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", *mBootNext
);
168 BootOption
= BdsLibVariableToOption (&BootLists
, Buffer
);
171 // If fail to get boot option from variable, just return and do nothing.
173 if (BootOption
== NULL
) {
177 BootOption
->BootCurrent
= *mBootNext
;
180 // Parse the boot order to get boot option
182 BdsLibBuildOptionFromVar (&BootLists
, L
"BootOrder");
185 // When we didn't have chance to build boot option variables in the first
186 // full configuration boot (e.g.: Reset in the first page or in Device Manager),
187 // we have no boot options in the following mini configuration boot.
188 // Give the last chance to enumerate the boot options.
190 if (IsListEmpty (&BootLists
)) {
191 BdsLibEnumerateAllBootOption (&BootLists
);
194 Link
= BootLists
.ForwardLink
;
197 // Parameter check, make sure the loop will be valid
203 // Here we make the boot in a loop, every boot success will
204 // return to the front page
208 // Check the boot option list first
210 if (Link
== &BootLists
) {
212 // When LazyConIn enabled, signal connect ConIn event before enter UI
214 if (PcdGetBool (PcdConInConnectOnDemand
) && ConnectConInEvent
!= NULL
) {
215 gBS
->SignalEvent (ConnectConInEvent
);
219 // There are two ways to enter here:
220 // 1. There is no active boot option, give user chance to
221 // add new boot option
222 // 2. All the active boot option processed, and there is no
223 // one is success to boot, then we back here to allow user
224 // add new active boot option
227 PlatformBdsEnterFrontPage (Timeout
, FALSE
);
228 InitializeListHead (&BootLists
);
229 BdsLibBuildOptionFromVar (&BootLists
, L
"BootOrder");
230 Link
= BootLists
.ForwardLink
;
234 // Get the boot option from the link list
236 BootOption
= CR (Link
, BDS_COMMON_OPTION
, Link
, BDS_LOAD_OPTION_SIGNATURE
);
239 // According to EFI Specification, if a load option is not marked
240 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically
243 if (!IS_LOAD_OPTION_TYPE (BootOption
->Attribute
, LOAD_OPTION_ACTIVE
)) {
245 // skip the header of the link list, because it has no boot option
247 Link
= Link
->ForwardLink
;
251 // Make sure the boot option device path connected,
252 // but ignore the BBS device path
254 if (DevicePathType (BootOption
->DevicePath
) != BBS_DEVICE_PATH
) {
256 // Notes: the internal shell can not been connected with device path
257 // so we do not check the status here
259 BdsLibConnectDevicePath (BootOption
->DevicePath
);
263 // Restore to original mode before launching boot option.
265 BdsSetConsoleMode (FALSE
);
268 // All the driver options should have been processed since
269 // now boot will be performed.
271 Status
= BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
272 if (Status
!= EFI_SUCCESS
) {
274 // Call platform action to indicate the boot fail
276 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_FAILED
));
277 PlatformBdsBootFail (BootOption
, Status
, ExitData
, ExitDataSize
);
280 // Check the next boot option
282 Link
= Link
->ForwardLink
;
286 // Call platform action to indicate the boot success
288 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED
));
289 PlatformBdsBootSuccess (BootOption
);
292 // Boot success, then stop process the boot order, and
293 // present the boot manager menu, front page
297 // When LazyConIn enabled, signal connect ConIn Event before enter UI
299 if (PcdGetBool (PcdConInConnectOnDemand
) && ConnectConInEvent
!= NULL
) {
300 gBS
->SignalEvent (ConnectConInEvent
);
304 PlatformBdsEnterFrontPage (Timeout
, FALSE
);
307 // Rescan the boot option list, avoid potential risk of the boot
308 // option change in front page
311 LinkBootNext
= BootLists
.ForwardLink
;
314 InitializeListHead (&BootLists
);
315 if (LinkBootNext
!= NULL
) {
317 // Reserve the boot next option
319 InsertTailList (&BootLists
, LinkBootNext
);
322 BdsLibBuildOptionFromVar (&BootLists
, L
"BootOrder");
323 Link
= BootLists
.ForwardLink
;
331 Validate input console variable data.
333 If found the device path is not a valid device path, remove the variable.
335 @param VariableName Input console variable name.
339 BdsFormalizeConsoleVariable (
340 IN CHAR16
*VariableName
343 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
347 DevicePath
= BdsLibGetVariableAndSize (
349 &gEfiGlobalVariableGuid
,
352 if ((DevicePath
!= NULL
) && !IsDevicePathValid (DevicePath
, VariableSize
)) {
353 Status
= gRT
->SetVariable (
355 &gEfiGlobalVariableGuid
,
356 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
360 ASSERT_EFI_ERROR (Status
);
366 Formalize Bds global variables.
368 1. For ConIn/ConOut/ConErr, if found the device path is not a valid device path, remove the variable.
369 2. For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps
370 3. Delete OsIndications variable if it is not NV/BS/RT UINT64
371 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.
375 BdsFormalizeEfiGlobalVariable (
380 UINT64 OsIndicationSupport
;
386 // Validate Console variable.
388 BdsFormalizeConsoleVariable (L
"ConIn");
389 BdsFormalizeConsoleVariable (L
"ConOut");
390 BdsFormalizeConsoleVariable (L
"ErrOut");
393 // OS indicater support variable
395 OsIndicationSupport
= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
396 Status
= gRT
->SetVariable (
397 L
"OsIndicationsSupported",
398 &gEfiGlobalVariableGuid
,
399 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
403 ASSERT_EFI_ERROR (Status
);
406 // If OsIndications is invalid, remove it.
408 // 1. Data size != UINT64
409 // 2. OsIndication value inconsistence
410 // 3. OsIndication attribute inconsistence
414 DataSize
= sizeof(UINT64
);
415 Status
= gRT
->GetVariable (
417 &gEfiGlobalVariableGuid
,
423 if (!EFI_ERROR(Status
)) {
424 if (DataSize
!= sizeof(UINT64
) ||
425 (OsIndication
& ~OsIndicationSupport
) != 0 ||
426 Attributes
!= (EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
)){
428 DEBUG ((EFI_D_ERROR
, "Unformalized OsIndications variable exists. Delete it\n"));
429 Status
= gRT
->SetVariable (
431 &gEfiGlobalVariableGuid
,
436 ASSERT_EFI_ERROR (Status
);
444 Service routine for BdsInstance->Entry(). Devices are connected, the
445 consoles are initialized, and the boot options are tried.
447 @param This Protocol Instance structure.
453 IN EFI_BDS_ARCH_PROTOCOL
*This
456 LIST_ENTRY DriverOptionList
;
457 LIST_ENTRY BootOptionList
;
459 CHAR16
*FirmwareVendor
;
462 // Insert the performance probe
464 PERF_END (NULL
, "DXE", NULL
, 0);
465 PERF_START (NULL
, "BDS", NULL
, 0);
468 // Initialize the global system boot option and driver option
470 InitializeListHead (&DriverOptionList
);
471 InitializeListHead (&BootOptionList
);
474 // Initialize hotkey service
476 InitializeHotkeyService ();
479 // Fill in FirmwareVendor and FirmwareRevision from PCDs
481 FirmwareVendor
= (CHAR16
*)PcdGetPtr (PcdFirmwareVendor
);
482 gST
->FirmwareVendor
= AllocateRuntimeCopyPool (StrSize (FirmwareVendor
), FirmwareVendor
);
483 ASSERT (gST
->FirmwareVendor
!= NULL
);
484 gST
->FirmwareRevision
= PcdGet32 (PcdFirmwareRevision
);
487 // Fixup Tasble CRC after we updated Firmware Vendor and Revision
490 gBS
->CalculateCrc32 ((VOID
*)gST
, sizeof(EFI_SYSTEM_TABLE
), &gST
->Hdr
.CRC32
);
493 // Validate Variable.
495 BdsFormalizeEfiGlobalVariable();
498 // Report Status Code to indicate connecting drivers will happen
502 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS
)
506 // Do the platform init, can be customized by OEM/IBV
508 PERF_START (NULL
, "PlatformBds", "BDS", 0);
511 InitializeHwErrRecSupport();
514 // bugbug: platform specific code
515 // Initialize the platform specific string and language
517 InitializeStringSupport ();
518 InitializeLanguage (TRUE
);
519 InitializeFrontPage (TRUE
);
522 // Set up the device list based on EFI 1.1 variables
523 // process Driver#### and Load the driver's in the
524 // driver option list
526 BdsLibBuildOptionFromVar (&DriverOptionList
, L
"DriverOrder");
527 if (!IsListEmpty (&DriverOptionList
)) {
528 BdsLibLoadDrivers (&DriverOptionList
);
531 // Check if we have the boot next option
533 mBootNext
= BdsLibGetVariableAndSize (
535 &gEfiGlobalVariableGuid
,
540 // Setup some platform policy here
542 PlatformBdsPolicyBehavior (&DriverOptionList
, &BootOptionList
, BdsProcessCapsules
, BdsMemoryTest
);
543 PERF_END (NULL
, "PlatformBds", "BDS", 0);
546 // BDS select the boot device to load OS
548 BdsBootDeviceSelect ();
551 // Only assert here since this is the right behavior, we should never
552 // return back to DxeCore.