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
;
42 /// The read-only variables defined in UEFI Spec.
44 CHAR16
*mReadOnlyVariables
[] = {
49 L
"OsIndicationsSupported"
54 Install Boot Device Selection Protocol
56 @param ImageHandle The image handle.
57 @param SystemTable The system table.
59 @retval EFI_SUCEESS BDS has finished initializing.
60 Return the dispatcher and recall BDS.Entry
61 @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface
67 IN EFI_HANDLE ImageHandle
,
68 IN EFI_SYSTEM_TABLE
*SystemTable
74 // Install protocol interface
76 Status
= gBS
->InstallMultipleProtocolInterfaces (
78 &gEfiBdsArchProtocolGuid
, &gBds
,
81 ASSERT_EFI_ERROR (Status
);
88 An empty function to pass error checking of CreateEventEx ().
90 @param Event Event whose notification function is being invoked.
91 @param Context Pointer to the notification function's context,
92 which is implementation-dependent.
97 BdsEmptyCallbackFunction (
106 This function attempts to boot for the boot order specified
111 BdsBootDeviceSelect (
117 BDS_COMMON_OPTION
*BootOption
;
121 LIST_ENTRY BootLists
;
123 BOOLEAN BootNextExist
;
124 LIST_ENTRY
*LinkBootNext
;
125 EFI_EVENT ConnectConInEvent
;
128 // Got the latest boot option
130 BootNextExist
= FALSE
;
132 ConnectConInEvent
= NULL
;
133 InitializeListHead (&BootLists
);
136 // First check the boot next option
138 ZeroMem (Buffer
, sizeof (Buffer
));
141 // Create Event to signal ConIn connection request
143 if (PcdGetBool (PcdConInConnectOnDemand
)) {
144 Status
= gBS
->CreateEventEx (
147 BdsEmptyCallbackFunction
,
149 &gConnectConInEventGuid
,
152 if (EFI_ERROR(Status
)) {
153 ConnectConInEvent
= NULL
;
157 if (mBootNext
!= NULL
) {
159 // Indicate we have the boot next variable, so this time
160 // boot will always have this boot option
162 BootNextExist
= TRUE
;
165 // Clear the this variable so it's only exist in this time boot
169 &gEfiGlobalVariableGuid
,
170 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
176 // Add the boot next boot option
178 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", *mBootNext
);
179 BootOption
= BdsLibVariableToOption (&BootLists
, Buffer
);
182 // If fail to get boot option from variable, just return and do nothing.
184 if (BootOption
== NULL
) {
188 BootOption
->BootCurrent
= *mBootNext
;
191 // Parse the boot order to get boot option
193 BdsLibBuildOptionFromVar (&BootLists
, L
"BootOrder");
196 // When we didn't have chance to build boot option variables in the first
197 // full configuration boot (e.g.: Reset in the first page or in Device Manager),
198 // we have no boot options in the following mini configuration boot.
199 // Give the last chance to enumerate the boot options.
201 if (IsListEmpty (&BootLists
)) {
202 BdsLibEnumerateAllBootOption (&BootLists
);
205 Link
= BootLists
.ForwardLink
;
208 // Parameter check, make sure the loop will be valid
214 // Here we make the boot in a loop, every boot success will
215 // return to the front page
219 // Check the boot option list first
221 if (Link
== &BootLists
) {
223 // When LazyConIn enabled, signal connect ConIn event before enter UI
225 if (PcdGetBool (PcdConInConnectOnDemand
) && ConnectConInEvent
!= NULL
) {
226 gBS
->SignalEvent (ConnectConInEvent
);
230 // There are two ways to enter here:
231 // 1. There is no active boot option, give user chance to
232 // add new boot option
233 // 2. All the active boot option processed, and there is no
234 // one is success to boot, then we back here to allow user
235 // add new active boot option
238 PlatformBdsEnterFrontPage (Timeout
, FALSE
);
239 InitializeListHead (&BootLists
);
240 BdsLibBuildOptionFromVar (&BootLists
, L
"BootOrder");
241 Link
= BootLists
.ForwardLink
;
245 // Get the boot option from the link list
247 BootOption
= CR (Link
, BDS_COMMON_OPTION
, Link
, BDS_LOAD_OPTION_SIGNATURE
);
250 // According to EFI Specification, if a load option is not marked
251 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically
254 if (!IS_LOAD_OPTION_TYPE (BootOption
->Attribute
, LOAD_OPTION_ACTIVE
)) {
256 // skip the header of the link list, because it has no boot option
258 Link
= Link
->ForwardLink
;
262 // Make sure the boot option device path connected,
263 // but ignore the BBS device path
265 if (DevicePathType (BootOption
->DevicePath
) != BBS_DEVICE_PATH
) {
267 // Notes: the internal shell can not been connected with device path
268 // so we do not check the status here
270 BdsLibConnectDevicePath (BootOption
->DevicePath
);
274 // Restore to original mode before launching boot option.
276 BdsSetConsoleMode (FALSE
);
279 // All the driver options should have been processed since
280 // now boot will be performed.
282 Status
= BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
283 if (Status
!= EFI_SUCCESS
) {
285 // Call platform action to indicate the boot fail
287 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_FAILED
));
288 PlatformBdsBootFail (BootOption
, Status
, ExitData
, ExitDataSize
);
291 // Check the next boot option
293 Link
= Link
->ForwardLink
;
297 // Call platform action to indicate the boot success
299 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED
));
300 PlatformBdsBootSuccess (BootOption
);
303 // Boot success, then stop process the boot order, and
304 // present the boot manager menu, front page
308 // When LazyConIn enabled, signal connect ConIn Event before enter UI
310 if (PcdGetBool (PcdConInConnectOnDemand
) && ConnectConInEvent
!= NULL
) {
311 gBS
->SignalEvent (ConnectConInEvent
);
315 PlatformBdsEnterFrontPage (Timeout
, FALSE
);
318 // Rescan the boot option list, avoid potential risk of the boot
319 // option change in front page
322 LinkBootNext
= BootLists
.ForwardLink
;
325 InitializeListHead (&BootLists
);
326 if (LinkBootNext
!= NULL
) {
328 // Reserve the boot next option
330 InsertTailList (&BootLists
, LinkBootNext
);
333 BdsLibBuildOptionFromVar (&BootLists
, L
"BootOrder");
334 Link
= BootLists
.ForwardLink
;
342 Validate input console variable data.
344 If found the device path is not a valid device path, remove the variable.
346 @param VariableName Input console variable name.
350 BdsFormalizeConsoleVariable (
351 IN CHAR16
*VariableName
354 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
358 DevicePath
= BdsLibGetVariableAndSize (
360 &gEfiGlobalVariableGuid
,
363 if ((DevicePath
!= NULL
) && !IsDevicePathValid (DevicePath
, VariableSize
)) {
364 Status
= gRT
->SetVariable (
366 &gEfiGlobalVariableGuid
,
367 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
371 ASSERT_EFI_ERROR (Status
);
377 Formalize Bds global variables.
379 1. For ConIn/ConOut/ConErr, if found the device path is not a valid device path, remove the variable.
380 2. For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps
381 3. Delete OsIndications variable if it is not NV/BS/RT UINT64
382 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.
386 BdsFormalizeEfiGlobalVariable (
391 UINT64 OsIndicationSupport
;
397 // Validate Console variable.
399 BdsFormalizeConsoleVariable (L
"ConIn");
400 BdsFormalizeConsoleVariable (L
"ConOut");
401 BdsFormalizeConsoleVariable (L
"ErrOut");
404 // OS indicater support variable
406 OsIndicationSupport
= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
407 Status
= gRT
->SetVariable (
408 L
"OsIndicationsSupported",
409 &gEfiGlobalVariableGuid
,
410 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
414 ASSERT_EFI_ERROR (Status
);
417 // If OsIndications is invalid, remove it.
419 // 1. Data size != UINT64
420 // 2. OsIndication value inconsistence
421 // 3. OsIndication attribute inconsistence
425 DataSize
= sizeof(UINT64
);
426 Status
= gRT
->GetVariable (
428 &gEfiGlobalVariableGuid
,
434 if (!EFI_ERROR(Status
)) {
435 if (DataSize
!= sizeof(UINT64
) ||
436 (OsIndication
& ~OsIndicationSupport
) != 0 ||
437 Attributes
!= (EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
)){
439 DEBUG ((EFI_D_ERROR
, "Unformalized OsIndications variable exists. Delete it\n"));
440 Status
= gRT
->SetVariable (
442 &gEfiGlobalVariableGuid
,
447 ASSERT_EFI_ERROR (Status
);
455 Allocate a block of memory that will contain performance data to OS.
459 BdsAllocateMemoryForPerformanceData (
464 EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase
;
465 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
467 AcpiLowMemoryBase
= 0x0FFFFFFFFULL
;
470 // Allocate a block of memory that will contain performance data to OS.
472 Status
= gBS
->AllocatePages (
474 EfiReservedMemoryType
,
475 EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH
),
478 if (!EFI_ERROR (Status
)) {
480 // Save the pointer to variable for use in S3 resume.
482 Status
= gRT
->SetVariable (
484 &gPerformanceProtocolGuid
,
485 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
486 sizeof (EFI_PHYSICAL_ADDRESS
),
489 ASSERT_EFI_ERROR (Status
);
491 // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists
493 Status
= gBS
->LocateProtocol (&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**) &VariableLock
);
494 if (!EFI_ERROR (Status
)) {
495 Status
= VariableLock
->RequestToLock (VariableLock
, L
"PerfDataMemAddr", &gPerformanceProtocolGuid
);
496 ASSERT_EFI_ERROR (Status
);
503 Service routine for BdsInstance->Entry(). Devices are connected, the
504 consoles are initialized, and the boot options are tried.
506 @param This Protocol Instance structure.
512 IN EFI_BDS_ARCH_PROTOCOL
*This
515 LIST_ENTRY DriverOptionList
;
516 LIST_ENTRY BootOptionList
;
518 CHAR16
*FirmwareVendor
;
522 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
525 // Insert the performance probe
527 PERF_END (NULL
, "DXE", NULL
, 0);
528 PERF_START (NULL
, "BDS", NULL
, 0);
531 BdsAllocateMemoryForPerformanceData ();
535 // Initialize the global system boot option and driver option
537 InitializeListHead (&DriverOptionList
);
538 InitializeListHead (&BootOptionList
);
541 // Initialize hotkey service
543 InitializeHotkeyService ();
546 // Fill in FirmwareVendor and FirmwareRevision from PCDs
548 FirmwareVendor
= (CHAR16
*)PcdGetPtr (PcdFirmwareVendor
);
549 gST
->FirmwareVendor
= AllocateRuntimeCopyPool (StrSize (FirmwareVendor
), FirmwareVendor
);
550 ASSERT (gST
->FirmwareVendor
!= NULL
);
551 gST
->FirmwareRevision
= PcdGet32 (PcdFirmwareRevision
);
554 // Fixup Tasble CRC after we updated Firmware Vendor and Revision
557 gBS
->CalculateCrc32 ((VOID
*)gST
, sizeof(EFI_SYSTEM_TABLE
), &gST
->Hdr
.CRC32
);
560 // Validate Variable.
562 BdsFormalizeEfiGlobalVariable();
565 // Mark the read-only variables if the Variable Lock protocol exists
567 Status
= gBS
->LocateProtocol (&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**) &VariableLock
);
568 DEBUG ((EFI_D_INFO
, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status
));
569 if (!EFI_ERROR (Status
)) {
570 for (Index
= 0; Index
< sizeof (mReadOnlyVariables
) / sizeof (mReadOnlyVariables
[0]); Index
++) {
571 Status
= VariableLock
->RequestToLock (VariableLock
, mReadOnlyVariables
[Index
], &gEfiGlobalVariableGuid
);
572 ASSERT_EFI_ERROR (Status
);
577 // Report Status Code to indicate connecting drivers will happen
581 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS
)
584 InitializeHwErrRecSupport();
587 // Initialize L"Timeout" EFI global variable.
589 BootTimeOut
= PcdGet16 (PcdPlatformBootTimeOut
);
590 if (BootTimeOut
!= 0xFFFF) {
592 // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification
593 // define same behavior between no value or 0xFFFF value for L"Timeout".
595 Status
= gRT
->SetVariable (
597 &gEfiGlobalVariableGuid
,
598 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
602 ASSERT_EFI_ERROR(Status
);
606 // bugbug: platform specific code
607 // Initialize the platform specific string and language
609 InitializeStringSupport ();
610 InitializeLanguage (TRUE
);
611 InitializeFrontPage (TRUE
);
614 // Do the platform init, can be customized by OEM/IBV
616 PERF_START (NULL
, "PlatformBds", "BDS", 0);
620 // Set up the device list based on EFI 1.1 variables
621 // process Driver#### and Load the driver's in the
622 // driver option list
624 BdsLibBuildOptionFromVar (&DriverOptionList
, L
"DriverOrder");
625 if (!IsListEmpty (&DriverOptionList
)) {
626 BdsLibLoadDrivers (&DriverOptionList
);
629 // Check if we have the boot next option
631 mBootNext
= BdsLibGetVariableAndSize (
633 &gEfiGlobalVariableGuid
,
638 // Setup some platform policy here
640 PlatformBdsPolicyBehavior (&DriverOptionList
, &BootOptionList
, BdsProcessCapsules
, BdsMemoryTest
);
641 PERF_END (NULL
, "PlatformBds", "BDS", 0);
644 // BDS select the boot device to load OS
646 BdsBootDeviceSelect ();
649 // Only assert here since this is the right behavior, we should never
650 // return back to DxeCore.