2009-01-23 08:24:55 +01:00
|
|
|
/** @file
|
|
|
|
This module produce main entry for BDS phase - BdsEntry.
|
|
|
|
When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed
|
|
|
|
which contains interface of BdsEntry.
|
|
|
|
After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked
|
|
|
|
to enter BDS phase.
|
|
|
|
|
|
|
|
Copyright (c) 2004 - 2008, Intel Corporation. <BR>
|
|
|
|
All rights reserved. This program and the accompanying materials
|
|
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "Bds.h"
|
|
|
|
#include "Language.h"
|
|
|
|
#include "FrontPage.h"
|
|
|
|
#include "Hotkey.h"
|
|
|
|
#include "HwErrRecSupport.h"
|
|
|
|
|
|
|
|
///
|
|
|
|
/// BDS arch protocol instance initial value.
|
|
|
|
///
|
|
|
|
/// Note: Current BDS not directly get the BootMode, DefaultBoot,
|
|
|
|
/// TimeoutDefault, MemoryTestLevel value from the BDS arch protocol.
|
|
|
|
/// Please refer to the library useage of BdsLibGetBootMode, BdsLibGetTimeout
|
|
|
|
/// and PlatformBdsDiagnostics in BdsPlatform.c
|
|
|
|
///
|
|
|
|
EFI_BDS_ARCH_PROTOCOL_INSTANCE gBdsInstanceTemplate = {
|
|
|
|
EFI_BDS_ARCH_PROTOCOL_INSTANCE_SIGNATURE,
|
|
|
|
NULL,
|
|
|
|
{BdsEntry},
|
|
|
|
0xFFFF,
|
|
|
|
TRUE,
|
|
|
|
0,
|
|
|
|
EXTENSIVE
|
|
|
|
};
|
|
|
|
|
|
|
|
UINT16 *mBootNext = NULL;
|
|
|
|
|
|
|
|
EFI_HANDLE mBdsImageHandle;
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
Install Boot Device Selection Protocol
|
|
|
|
|
|
|
|
@param ImageHandle The image handle.
|
|
|
|
@param SystemTable The system table.
|
|
|
|
|
|
|
|
@retval EFI_SUCEESS BDS has finished initializing.
|
|
|
|
Return the dispatcher and recall BDS.Entry
|
|
|
|
@retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface
|
|
|
|
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
|
|
EFIAPI
|
|
|
|
BdsInitialize (
|
|
|
|
IN EFI_HANDLE ImageHandle,
|
|
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
mBdsImageHandle = ImageHandle;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Install protocol interface
|
|
|
|
//
|
|
|
|
Status = gBS->InstallProtocolInterface (
|
|
|
|
&gBdsInstanceTemplate.Handle,
|
|
|
|
&gEfiBdsArchProtocolGuid,
|
|
|
|
EFI_NATIVE_INTERFACE,
|
|
|
|
&gBdsInstanceTemplate.Bds
|
|
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
This function attempts to boot for the boot order specified
|
|
|
|
by platform policy.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
BdsBootDeviceSelect (
|
|
|
|
VOID
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
LIST_ENTRY *Link;
|
|
|
|
BDS_COMMON_OPTION *BootOption;
|
|
|
|
UINTN ExitDataSize;
|
|
|
|
CHAR16 *ExitData;
|
|
|
|
UINT16 Timeout;
|
|
|
|
LIST_ENTRY BootLists;
|
|
|
|
CHAR16 Buffer[20];
|
|
|
|
BOOLEAN BootNextExist;
|
|
|
|
LIST_ENTRY *LinkBootNext;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Got the latest boot option
|
|
|
|
//
|
|
|
|
BootNextExist = FALSE;
|
|
|
|
LinkBootNext = NULL;
|
|
|
|
InitializeListHead (&BootLists);
|
|
|
|
|
|
|
|
//
|
|
|
|
// First check the boot next option
|
|
|
|
//
|
|
|
|
ZeroMem (Buffer, sizeof (Buffer));
|
|
|
|
|
|
|
|
if (mBootNext != NULL) {
|
|
|
|
//
|
|
|
|
// Indicate we have the boot next variable, so this time
|
|
|
|
// boot will always have this boot option
|
|
|
|
//
|
|
|
|
BootNextExist = TRUE;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Clear the this variable so it's only exist in this time boot
|
|
|
|
//
|
|
|
|
gRT->SetVariable (
|
|
|
|
L"BootNext",
|
|
|
|
&gEfiGlobalVariableGuid,
|
|
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
|
|
0,
|
|
|
|
mBootNext
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Add the boot next boot option
|
|
|
|
//
|
|
|
|
UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);
|
|
|
|
BootOption = BdsLibVariableToOption (&BootLists, Buffer);
|
|
|
|
|
|
|
|
//
|
|
|
|
// If fail to get boot option from variable, just return and do nothing.
|
|
|
|
//
|
|
|
|
if (BootOption == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BootOption->BootCurrent = *mBootNext;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Parse the boot order to get boot option
|
|
|
|
//
|
|
|
|
BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
|
|
|
|
Link = BootLists.ForwardLink;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Parameter check, make sure the loop will be valid
|
|
|
|
//
|
|
|
|
if (Link == NULL) {
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Here we make the boot in a loop, every boot success will
|
|
|
|
// return to the front page
|
|
|
|
//
|
|
|
|
for (;;) {
|
|
|
|
//
|
|
|
|
// Check the boot option list first
|
|
|
|
//
|
|
|
|
if (Link == &BootLists) {
|
|
|
|
//
|
|
|
|
// There are two ways to enter here:
|
|
|
|
// 1. There is no active boot option, give user chance to
|
|
|
|
// add new boot option
|
|
|
|
// 2. All the active boot option processed, and there is no
|
|
|
|
// one is success to boot, then we back here to allow user
|
|
|
|
// add new active boot option
|
|
|
|
//
|
|
|
|
Timeout = 0xffff;
|
|
|
|
PlatformBdsEnterFrontPage (Timeout, FALSE);
|
|
|
|
InitializeListHead (&BootLists);
|
|
|
|
BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
|
|
|
|
Link = BootLists.ForwardLink;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Get the boot option from the link list
|
|
|
|
//
|
|
|
|
BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
|
|
|
|
|
|
|
|
//
|
|
|
|
// According to EFI Specification, if a load option is not marked
|
|
|
|
// as LOAD_OPTION_ACTIVE, the boot manager will not automatically
|
|
|
|
// load the option.
|
|
|
|
//
|
|
|
|
if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {
|
|
|
|
//
|
|
|
|
// skip the header of the link list, becuase it has no boot option
|
|
|
|
//
|
|
|
|
Link = Link->ForwardLink;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Make sure the boot option device path connected,
|
|
|
|
// but ignore the BBS device path
|
|
|
|
//
|
|
|
|
if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {
|
|
|
|
//
|
|
|
|
// Notes: the internal shell can not been connected with device path
|
|
|
|
// so we do not check the status here
|
|
|
|
//
|
|
|
|
BdsLibConnectDevicePath (BootOption->DevicePath);
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// All the driver options should have been processed since
|
|
|
|
// now boot will be performed.
|
|
|
|
//
|
|
|
|
Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
//
|
|
|
|
// Call platform action to indicate the boot fail
|
|
|
|
//
|
|
|
|
BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
|
|
|
|
PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Check the next boot option
|
|
|
|
//
|
|
|
|
Link = Link->ForwardLink;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
//
|
|
|
|
// Call platform action to indicate the boot success
|
|
|
|
//
|
|
|
|
BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
|
|
|
|
PlatformBdsBootSuccess (BootOption);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Boot success, then stop process the boot order, and
|
|
|
|
// present the boot manager menu, front page
|
|
|
|
//
|
|
|
|
Timeout = 0xffff;
|
|
|
|
PlatformBdsEnterFrontPage (Timeout, FALSE);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Rescan the boot option list, avoid pertential risk of the boot
|
|
|
|
// option change in front page
|
|
|
|
//
|
|
|
|
if (BootNextExist) {
|
|
|
|
LinkBootNext = BootLists.ForwardLink;
|
|
|
|
}
|
|
|
|
|
|
|
|
InitializeListHead (&BootLists);
|
|
|
|
if (LinkBootNext != NULL) {
|
|
|
|
//
|
|
|
|
// Reserve the boot next option
|
|
|
|
//
|
|
|
|
InsertTailList (&BootLists, LinkBootNext);
|
|
|
|
}
|
|
|
|
|
|
|
|
BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
|
|
|
|
Link = BootLists.ForwardLink;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
Service routine for BdsInstance->Entry(). Devices are connected, the
|
|
|
|
consoles are initialized, and the boot options are tried.
|
|
|
|
|
|
|
|
@param This Protocol Instance structure.
|
|
|
|
|
|
|
|
**/
|
|
|
|
VOID
|
|
|
|
EFIAPI
|
|
|
|
BdsEntry (
|
|
|
|
IN EFI_BDS_ARCH_PROTOCOL *This
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData;
|
|
|
|
LIST_ENTRY DriverOptionList;
|
|
|
|
LIST_ENTRY BootOptionList;
|
|
|
|
UINTN BootNextSize;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Insert the performance probe
|
|
|
|
//
|
2009-02-23 04:14:12 +01:00
|
|
|
PERF_END (0, "DXE", NULL, 0);
|
|
|
|
PERF_START (0, "BDS", NULL, 0);
|
2009-01-23 08:24:55 +01:00
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize the global system boot option and driver option
|
|
|
|
//
|
|
|
|
InitializeListHead (&DriverOptionList);
|
|
|
|
InitializeListHead (&BootOptionList);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize hotkey service
|
|
|
|
//
|
|
|
|
InitializeHotkeyService ();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get the BDS private data
|
|
|
|
//
|
|
|
|
PrivateData = EFI_BDS_ARCH_PROTOCOL_INSTANCE_FROM_THIS (This);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Do the platform init, can be customized by OEM/IBV
|
|
|
|
//
|
|
|
|
PERF_START (0, "PlatformBds", "BDS", 0);
|
|
|
|
PlatformBdsInit (PrivateData);
|
|
|
|
|
2009-02-26 09:19:38 +01:00
|
|
|
InitializeHwErrRecSupport();
|
|
|
|
|
2009-01-23 08:24:55 +01:00
|
|
|
//
|
|
|
|
// bugbug: platform specific code
|
|
|
|
// Initialize the platform specific string and language
|
|
|
|
//
|
|
|
|
InitializeStringSupport ();
|
|
|
|
InitializeLanguage (TRUE);
|
|
|
|
InitializeFrontPage (TRUE);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Set up the device list based on EFI 1.1 variables
|
|
|
|
// process Driver#### and Load the driver's in the
|
|
|
|
// driver option list
|
|
|
|
//
|
|
|
|
BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");
|
|
|
|
if (!IsListEmpty (&DriverOptionList)) {
|
|
|
|
BdsLibLoadDrivers (&DriverOptionList);
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Check if we have the boot next option
|
|
|
|
//
|
|
|
|
mBootNext = BdsLibGetVariableAndSize (
|
|
|
|
L"BootNext",
|
|
|
|
&gEfiGlobalVariableGuid,
|
|
|
|
&BootNextSize
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Setup some platform policy here
|
|
|
|
//
|
|
|
|
PlatformBdsPolicyBehavior (PrivateData, &DriverOptionList, &BootOptionList);
|
|
|
|
PERF_END (0, "PlatformBds", "BDS", 0);
|
|
|
|
|
|
|
|
//
|
|
|
|
// BDS select the boot device to load OS
|
|
|
|
//
|
|
|
|
BdsBootDeviceSelect ();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Only assert here since this is the right behavior, we should never
|
|
|
|
// return back to DxeCore.
|
|
|
|
//
|
|
|
|
ASSERT (FALSE);
|
|
|
|
|
|
|
|
return ;
|
|
|
|
}
|