--- /dev/null
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation \r
+All rights reserved. This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php \r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+Module Name:\r
+\r
+ BdsEntry.c\r
+\r
+Abstract:\r
+\r
+ The entry of the bds\r
+\r
+--*/\r
+\r
+#include "Bds.h"\r
+#include "BdsPlatform.h"\r
+#include "FrontPage.h"\r
+\r
+EFI_BDS_ARCH_PROTOCOL_INSTANCE gBdsInstanceTemplate = {\r
+ EFI_BDS_ARCH_PROTOCOL_INSTANCE_SIGNATURE,\r
+ NULL,\r
+ BdsEntry,\r
+ 0xFFFF,\r
+ TRUE,\r
+ EXTENSIVE\r
+};\r
+\r
+UINT16 *mBootNext = NULL;\r
+\r
+EFI_HANDLE mBdsImageHandle;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+BdsInitialize (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Install Boot Device Selection Protocol\r
+\r
+Arguments:\r
+ \r
+ (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)\r
+\r
+Returns:\r
+\r
+ EFI_SUCEESS - BDS has finished initializing.\r
+ Rerun the \r
+ dispatcher and recall BDS.Entry\r
+\r
+ Other - Return value from EfiLibAllocatePool()\r
+ or gBS->InstallProtocolInterface\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ mBdsImageHandle = ImageHandle;\r
+\r
+ //\r
+ // Install protocol interface\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &gBdsInstanceTemplate.Handle,\r
+ &gEfiBdsArchProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &gBdsInstanceTemplate.Bds\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r
+VOID\r
+BdsBootDeviceSelect (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ In the loop of attempt to boot for the boot order\r
+\r
+Arguments:\r
+ \r
+ None.\r
+\r
+Returns:\r
+\r
+ None.\r
+ \r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Link;\r
+ BDS_COMMON_OPTION *BootOption;\r
+ UINTN ExitDataSize;\r
+ CHAR16 *ExitData;\r
+ UINT16 Timeout;\r
+ LIST_ENTRY BootLists;\r
+ CHAR16 Buffer[20];\r
+ BOOLEAN BootNextExist;\r
+ LIST_ENTRY *LinkBootNext;\r
+\r
+ //\r
+ // Got the latest boot option\r
+ //\r
+ BootNextExist = FALSE;\r
+ LinkBootNext = NULL;\r
+ InitializeListHead (&BootLists);\r
+\r
+ //\r
+ // First check the boot next option\r
+ //\r
+ ZeroMem (Buffer, sizeof (Buffer));\r
+\r
+ if (mBootNext != NULL) {\r
+ //\r
+ // Indicate we have the boot next variable, so this time\r
+ // boot will always have this boot option\r
+ //\r
+ BootNextExist = TRUE;\r
+\r
+ //\r
+ // Clear the this variable so it's only exist in this time boot\r
+ //\r
+ gRT->SetVariable (\r
+ L"BootNext",\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+ 0,\r
+ mBootNext\r
+ );\r
+\r
+ //\r
+ // Add the boot next boot option\r
+ //\r
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);\r
+ BootOption = BdsLibVariableToOption (&BootLists, Buffer);\r
+ }\r
+ //\r
+ // Parse the boot order to get boot option\r
+ //\r
+ BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
+ Link = BootLists.ForwardLink;\r
+\r
+ //\r
+ // Parameter check, make sure the loop will be valid\r
+ //\r
+ if (Link == NULL) {\r
+ return ;\r
+ }\r
+ //\r
+ // Here we make the boot in a loop, every boot success will\r
+ // return to the front page\r
+ //\r
+ for (;;) {\r
+ //\r
+ // Check the boot option list first\r
+ //\r
+ if (Link == &BootLists) {\r
+ //\r
+ // There are two ways to enter here:\r
+ // 1. There is no active boot option, give user chance to\r
+ // add new boot option\r
+ // 2. All the active boot option processed, and there is no\r
+ // one is success to boot, then we back here to allow user\r
+ // add new active boot option\r
+ //\r
+ Timeout = 0xffff;\r
+ PlatformBdsEnterFrontPage (Timeout, FALSE);\r
+ InitializeListHead (&BootLists);\r
+ BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
+ Link = BootLists.ForwardLink;\r
+ continue;\r
+ }\r
+ //\r
+ // Get the boot option from the link list\r
+ //\r
+ BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);\r
+\r
+ //\r
+ // According to EFI Specification, if a load option is not marked\r
+ // as LOAD_OPTION_ACTIVE, the boot manager will not automatically\r
+ // load the option.\r
+ //\r
+ if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {\r
+ //\r
+ // skip the header of the link list, becuase it has no boot option\r
+ //\r
+ Link = Link->ForwardLink;\r
+ continue;\r
+ }\r
+ //\r
+ // Make sure the boot option device path connected,\r
+ // but ignore the BBS device path\r
+ //\r
+ if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {\r
+ //\r
+ // Notes: the internal shell can not been connected with device path\r
+ // so we do not check the status here\r
+ //\r
+ BdsLibConnectDevicePath (BootOption->DevicePath);\r
+ }\r
+ //\r
+ // All the driver options should have been processed since\r
+ // now boot will be performed.\r
+ //\r
+ PERF_END (0, BDS_TOK, NULL, 0);\r
+ Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Call platform action to indicate the boot fail\r
+ //\r
+ PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);\r
+\r
+ //\r
+ // Check the next boot option\r
+ //\r
+ Link = Link->ForwardLink;\r
+\r
+ } else {\r
+ //\r
+ // Call platform action to indicate the boot success\r
+ //\r
+ PlatformBdsBootSuccess (BootOption);\r
+\r
+ //\r
+ // Boot success, then stop process the boot order, and\r
+ // present the boot manager menu, front page\r
+ //\r
+ Timeout = 0xffff;\r
+ PlatformBdsEnterFrontPage (Timeout, FALSE);\r
+\r
+ //\r
+ // Rescan the boot option list, avoid pertential risk of the boot\r
+ // option change in front page\r
+ //\r
+ if (BootNextExist) {\r
+ LinkBootNext = BootLists.ForwardLink;\r
+ }\r
+\r
+ InitializeListHead (&BootLists);\r
+ if (LinkBootNext != NULL) {\r
+ //\r
+ // Reserve the boot next option\r
+ //\r
+ InsertTailList (&BootLists, LinkBootNext);\r
+ }\r
+\r
+ BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");\r
+ Link = BootLists.ForwardLink;\r
+ }\r
+ }\r
+\r
+ return ;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+BdsEntry (\r
+ IN EFI_BDS_ARCH_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Service routine for BdsInstance->Entry(). Devices are connected, the \r
+ consoles are initialized, and the boot options are tried. \r
+\r
+Arguments:\r
+\r
+ This - Protocol Instance structure.\r
+\r
+Returns:\r
+\r
+ EFI_SUCEESS - BDS->Entry has finished executing. \r
+ \r
+--*/\r
+{\r
+ EFI_BDS_ARCH_PROTOCOL_INSTANCE *PrivateData;\r
+ LIST_ENTRY DriverOptionList;\r
+ LIST_ENTRY BootOptionList;\r
+ UINTN BootNextSize;\r
+\r
+ //\r
+ // Insert the performance probe\r
+ //\r
+ PERF_END (0, DXE_TOK, NULL, 0);\r
+ PERF_START (0, BDS_TOK, NULL, 0);\r
+\r
+ //\r
+ // Initialize the global system boot option and driver option\r
+ //\r
+ InitializeListHead (&DriverOptionList);\r
+ InitializeListHead (&BootOptionList);\r
+\r
+ //\r
+ // Get the BDS private data\r
+ //\r
+ PrivateData = EFI_BDS_ARCH_PROTOCOL_INSTANCE_FROM_THIS (This);\r
+\r
+ //\r
+ // Do the platform init, can be customized by OEM/IBV\r
+ //\r
+ PERF_START (0, "PlatformBds", "BDS", 0);\r
+ PlatformBdsInit (PrivateData);\r
+\r
+ //\r
+ // Set up the device list based on EFI 1.1 variables\r
+ // process Driver#### and Load the driver's in the\r
+ // driver option list\r
+ //\r
+ BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");\r
+ if (!IsListEmpty (&DriverOptionList)) {\r
+ BdsLibLoadDrivers (&DriverOptionList);\r
+ }\r
+ //\r
+ // Check if we have the boot next option\r
+ //\r
+ mBootNext = BdsLibGetVariableAndSize (\r
+ L"BootNext",\r
+ &gEfiGlobalVariableGuid,\r
+ &BootNextSize\r
+ );\r
+\r
+ //\r
+ // Setup some platform policy here\r
+ //\r
+ PlatformBdsPolicyBehavior (PrivateData, &DriverOptionList, &BootOptionList);\r
+ PERF_END (0, L"PlatformBds", L"BDS", 0);\r
+\r
+ //\r
+ // BDS select the boot device to load OS\r
+ //\r
+ BdsBootDeviceSelect ();\r
+\r
+ //\r
+ // Only assert here since this is the right behavior, we should never\r
+ // return back to DxeCore.\r
+ //\r
+ ASSERT (FALSE);\r
+\r
+ return EFI_SUCCESS;\r
+}\r