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
;
464 // Insert the performance probe
466 PERF_END (NULL
, "DXE", NULL
, 0);
467 PERF_START (NULL
, "BDS", NULL
, 0);
470 // Initialize the global system boot option and driver option
472 InitializeListHead (&DriverOptionList
);
473 InitializeListHead (&BootOptionList
);
476 // Initialize hotkey service
478 InitializeHotkeyService ();
481 // Fill in FirmwareVendor and FirmwareRevision from PCDs
483 FirmwareVendor
= (CHAR16
*)PcdGetPtr (PcdFirmwareVendor
);
484 gST
->FirmwareVendor
= AllocateRuntimeCopyPool (StrSize (FirmwareVendor
), FirmwareVendor
);
485 ASSERT (gST
->FirmwareVendor
!= NULL
);
486 gST
->FirmwareRevision
= PcdGet32 (PcdFirmwareRevision
);
489 // Fixup Tasble CRC after we updated Firmware Vendor and Revision
492 gBS
->CalculateCrc32 ((VOID
*)gST
, sizeof(EFI_SYSTEM_TABLE
), &gST
->Hdr
.CRC32
);
495 // Validate Variable.
497 BdsFormalizeEfiGlobalVariable();
500 // Report Status Code to indicate connecting drivers will happen
504 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS
)
508 // Do the platform init, can be customized by OEM/IBV
510 PERF_START (NULL
, "PlatformBds", "BDS", 0);
513 InitializeHwErrRecSupport();
516 // Initialize L"Timeout" EFI global variable.
518 BootTimeOut
= PcdGet16 (PcdPlatformBootTimeOut
);
519 if (BootTimeOut
!= 0xFFFF) {
521 // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification
522 // define same behavior between no value or 0xFFFF value for L"Timeout".
524 Status
= gRT
->SetVariable (
526 &gEfiGlobalVariableGuid
,
527 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
531 ASSERT_EFI_ERROR(Status
);
535 // bugbug: platform specific code
536 // Initialize the platform specific string and language
538 InitializeStringSupport ();
539 InitializeLanguage (TRUE
);
540 InitializeFrontPage (TRUE
);
543 // Set up the device list based on EFI 1.1 variables
544 // process Driver#### and Load the driver's in the
545 // driver option list
547 BdsLibBuildOptionFromVar (&DriverOptionList
, L
"DriverOrder");
548 if (!IsListEmpty (&DriverOptionList
)) {
549 BdsLibLoadDrivers (&DriverOptionList
);
552 // Check if we have the boot next option
554 mBootNext
= BdsLibGetVariableAndSize (
556 &gEfiGlobalVariableGuid
,
561 // Setup some platform policy here
563 PlatformBdsPolicyBehavior (&DriverOptionList
, &BootOptionList
, BdsProcessCapsules
, BdsMemoryTest
);
564 PERF_END (NULL
, "PlatformBds", "BDS", 0);
567 // BDS select the boot device to load OS
569 BdsBootDeviceSelect ();
572 // Only assert here since this is the right behavior, we should never
573 // return back to DxeCore.