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 - 2012, 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 This function attempts to boot for the boot order specified
88 BDS_COMMON_OPTION
*BootOption
;
94 BOOLEAN BootNextExist
;
95 LIST_ENTRY
*LinkBootNext
;
98 // Got the latest boot option
100 BootNextExist
= FALSE
;
102 InitializeListHead (&BootLists
);
105 // First check the boot next option
107 ZeroMem (Buffer
, sizeof (Buffer
));
109 if (mBootNext
!= NULL
) {
111 // Indicate we have the boot next variable, so this time
112 // boot will always have this boot option
114 BootNextExist
= TRUE
;
117 // Clear the this variable so it's only exist in this time boot
121 &gEfiGlobalVariableGuid
,
122 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
128 // Add the boot next boot option
130 UnicodeSPrint (Buffer
, sizeof (Buffer
), L
"Boot%04x", *mBootNext
);
131 BootOption
= BdsLibVariableToOption (&BootLists
, Buffer
);
134 // If fail to get boot option from variable, just return and do nothing.
136 if (BootOption
== NULL
) {
140 BootOption
->BootCurrent
= *mBootNext
;
143 // Parse the boot order to get boot option
145 BdsLibBuildOptionFromVar (&BootLists
, L
"BootOrder");
148 // When we didn't have chance to build boot option variables in the first
149 // full configuration boot (e.g.: Reset in the first page or in Device Manager),
150 // we have no boot options in the following mini configuration boot.
151 // Give the last chance to enumerate the boot options.
153 if (IsListEmpty (&BootLists
)) {
154 BdsLibEnumerateAllBootOption (&BootLists
);
157 Link
= BootLists
.ForwardLink
;
160 // Parameter check, make sure the loop will be valid
166 // Here we make the boot in a loop, every boot success will
167 // return to the front page
171 // Check the boot option list first
173 if (Link
== &BootLists
) {
175 // There are two ways to enter here:
176 // 1. There is no active boot option, give user chance to
177 // add new boot option
178 // 2. All the active boot option processed, and there is no
179 // one is success to boot, then we back here to allow user
180 // add new active boot option
183 PlatformBdsEnterFrontPage (Timeout
, FALSE
);
184 InitializeListHead (&BootLists
);
185 BdsLibBuildOptionFromVar (&BootLists
, L
"BootOrder");
186 Link
= BootLists
.ForwardLink
;
190 // Get the boot option from the link list
192 BootOption
= CR (Link
, BDS_COMMON_OPTION
, Link
, BDS_LOAD_OPTION_SIGNATURE
);
195 // According to EFI Specification, if a load option is not marked
196 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically
199 if (!IS_LOAD_OPTION_TYPE (BootOption
->Attribute
, LOAD_OPTION_ACTIVE
)) {
201 // skip the header of the link list, because it has no boot option
203 Link
= Link
->ForwardLink
;
207 // Make sure the boot option device path connected,
208 // but ignore the BBS device path
210 if (DevicePathType (BootOption
->DevicePath
) != BBS_DEVICE_PATH
) {
212 // Notes: the internal shell can not been connected with device path
213 // so we do not check the status here
215 BdsLibConnectDevicePath (BootOption
->DevicePath
);
219 // Restore to original mode before launching boot option.
221 BdsSetConsoleMode (FALSE
);
224 // All the driver options should have been processed since
225 // now boot will be performed.
227 Status
= BdsLibBootViaBootOption (BootOption
, BootOption
->DevicePath
, &ExitDataSize
, &ExitData
);
228 if (Status
!= EFI_SUCCESS
) {
230 // Call platform action to indicate the boot fail
232 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_FAILED
));
233 PlatformBdsBootFail (BootOption
, Status
, ExitData
, ExitDataSize
);
236 // Check the next boot option
238 Link
= Link
->ForwardLink
;
242 // Call platform action to indicate the boot success
244 BootOption
->StatusString
= GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED
));
245 PlatformBdsBootSuccess (BootOption
);
248 // Boot success, then stop process the boot order, and
249 // present the boot manager menu, front page
252 PlatformBdsEnterFrontPage (Timeout
, FALSE
);
255 // Rescan the boot option list, avoid potential risk of the boot
256 // option change in front page
259 LinkBootNext
= BootLists
.ForwardLink
;
262 InitializeListHead (&BootLists
);
263 if (LinkBootNext
!= NULL
) {
265 // Reserve the boot next option
267 InsertTailList (&BootLists
, LinkBootNext
);
270 BdsLibBuildOptionFromVar (&BootLists
, L
"BootOrder");
271 Link
= BootLists
.ForwardLink
;
278 Validate the device path instance.
280 Only base on the length filed in the device path node to validate the device path.
282 @param DevicePath A pointer to a device path data structure.
283 @param MaxSize Max valid device path size. If big than this size,
286 @retval TRUE An valid device path.
287 @retval FALSE An invalid device path.
292 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
299 if (DevicePath
== NULL
) {
305 while (!IsDevicePathEnd (DevicePath
)) {
306 NodeSize
= DevicePathNodeLength (DevicePath
);
307 if (NodeSize
< END_DEVICE_PATH_LENGTH
) {
312 if (Size
> MaxSize
) {
316 DevicePath
= NextDevicePathNode (DevicePath
);
319 Size
+= DevicePathNodeLength (DevicePath
);
320 if (Size
> MaxSize
) {
329 Validate input console variable data.
331 If found the device path is not a valid device path, remove the variable.
333 @param VariableName Input console variable name.
337 BdsFormalizeConsoleVariable (
338 IN CHAR16
*VariableName
341 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
345 DevicePath
= BdsLibGetVariableAndSize (
347 &gEfiGlobalVariableGuid
,
350 if (!IsValidDevicePath (DevicePath
, VariableSize
)) {
351 Status
= gRT
->SetVariable (
353 &gEfiGlobalVariableGuid
,
354 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
,
358 ASSERT_EFI_ERROR (Status
);
364 Formalize Bds global variables.
366 1. For ConIn/ConOut/ConErr, if found the device path is not a valid device path, remove the variable.
367 2. For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps
368 3. Delete OsIndications variable if it is not NV/BS/RT UINT64
369 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.
373 BdsFormalizeEfiGlobalVariable (
378 UINT64 OsIndicationSupport
;
384 // Validate Console variable.
386 BdsFormalizeConsoleVariable (L
"ConIn");
387 BdsFormalizeConsoleVariable (L
"ConOut");
388 BdsFormalizeConsoleVariable (L
"ErrOut");
391 // OS indicater support variable
393 OsIndicationSupport
= EFI_OS_INDICATIONS_BOOT_TO_FW_UI
;
394 Status
= gRT
->SetVariable (
395 L
"OsIndicationsSupported",
396 &gEfiGlobalVariableGuid
,
397 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
401 ASSERT_EFI_ERROR (Status
);
404 // If OsIndications is invalid, remove it.
406 // 1. Data size != UINT64
407 // 2. OsIndication value inconsistence
408 // 3. OsIndication attribute inconsistence
412 DataSize
= sizeof(UINT64
);
413 Status
= gRT
->GetVariable (
415 &gEfiGlobalVariableGuid
,
421 if (!EFI_ERROR(Status
)) {
422 if (DataSize
!= sizeof(UINT64
) ||
423 (OsIndication
& ~OsIndicationSupport
) != 0 ||
424 Attributes
!= (EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
)){
426 DEBUG ((EFI_D_ERROR
, "Unformalized OsIndications variable exists. Delete it\n"));
427 Status
= gRT
->SetVariable (
429 &gEfiGlobalVariableGuid
,
434 ASSERT_EFI_ERROR (Status
);
442 Service routine for BdsInstance->Entry(). Devices are connected, the
443 consoles are initialized, and the boot options are tried.
445 @param This Protocol Instance structure.
451 IN EFI_BDS_ARCH_PROTOCOL
*This
454 LIST_ENTRY DriverOptionList
;
455 LIST_ENTRY BootOptionList
;
457 CHAR16
*FirmwareVendor
;
460 // Insert the performance probe
462 PERF_END (NULL
, "DXE", NULL
, 0);
463 PERF_START (NULL
, "BDS", NULL
, 0);
466 // Initialize the global system boot option and driver option
468 InitializeListHead (&DriverOptionList
);
469 InitializeListHead (&BootOptionList
);
472 // Initialize hotkey service
474 InitializeHotkeyService ();
477 // Fill in FirmwareVendor and FirmwareRevision from PCDs
479 FirmwareVendor
= (CHAR16
*)PcdGetPtr (PcdFirmwareVendor
);
480 gST
->FirmwareVendor
= AllocateRuntimeCopyPool (StrSize (FirmwareVendor
), FirmwareVendor
);
481 ASSERT (gST
->FirmwareVendor
!= NULL
);
482 gST
->FirmwareRevision
= PcdGet32 (PcdFirmwareRevision
);
485 // Fixup Tasble CRC after we updated Firmware Vendor and Revision
487 gBS
->CalculateCrc32 ((VOID
*)gST
, sizeof(EFI_SYSTEM_TABLE
), &gST
->Hdr
.CRC32
);
490 // Validate Variable.
492 BdsFormalizeEfiGlobalVariable();
495 // Do the platform init, can be customized by OEM/IBV
497 PERF_START (NULL
, "PlatformBds", "BDS", 0);
500 InitializeHwErrRecSupport();
503 // bugbug: platform specific code
504 // Initialize the platform specific string and language
506 InitializeStringSupport ();
507 InitializeLanguage (TRUE
);
508 InitializeFrontPage (TRUE
);
511 // Set up the device list based on EFI 1.1 variables
512 // process Driver#### and Load the driver's in the
513 // driver option list
515 BdsLibBuildOptionFromVar (&DriverOptionList
, L
"DriverOrder");
516 if (!IsListEmpty (&DriverOptionList
)) {
517 BdsLibLoadDrivers (&DriverOptionList
);
520 // Check if we have the boot next option
522 mBootNext
= BdsLibGetVariableAndSize (
524 &gEfiGlobalVariableGuid
,
529 // Setup some platform policy here
531 PlatformBdsPolicyBehavior (&DriverOptionList
, &BootOptionList
, BdsProcessCapsules
, BdsMemoryTest
);
532 PERF_END (NULL
, "PlatformBds", "BDS", 0);
535 // BDS select the boot device to load OS
537 BdsBootDeviceSelect ();
540 // Only assert here since this is the right behavior, we should never
541 // return back to DxeCore.