From f4cd24da284adfbac2aa471ed5624cf5782c632a Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 6 May 2015 04:48:56 +0000 Subject: [PATCH] MdeModulePkg: Add BdsDxe driver and PlatformBootManagerNull library. BdsDxe driver links to UefiBootManagerLib and PlatformBootManager to provide a pure UEFI boot manager conforming to the UEFI spec. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni Reviewed-by: Eric Dong git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17328 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Include/Library/PlatformBootManagerLib.h | 62 + .../PlatformBootManager.c | 67 + .../PlatformBootManagerLibNull.inf | 36 + MdeModulePkg/MdeModulePkg.dec | 3 + MdeModulePkg/MdeModulePkg.dsc | 4 + MdeModulePkg/Universal/BdsDxe/Bds.h | 106 ++ MdeModulePkg/Universal/BdsDxe/BdsDxe.inf | 101 ++ MdeModulePkg/Universal/BdsDxe/BdsEntry.c | 1246 +++++++++++++++++ .../Universal/BdsDxe/HwErrRecSupport.c | 48 + .../Universal/BdsDxe/HwErrRecSupport.h | 32 + MdeModulePkg/Universal/BdsDxe/Language.c | 202 +++ MdeModulePkg/Universal/BdsDxe/Language.h | 30 + 12 files changed, 1937 insertions(+) create mode 100644 MdeModulePkg/Include/Library/PlatformBootManagerLib.h create mode 100644 MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c create mode 100644 MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf create mode 100644 MdeModulePkg/Universal/BdsDxe/Bds.h create mode 100644 MdeModulePkg/Universal/BdsDxe/BdsDxe.inf create mode 100644 MdeModulePkg/Universal/BdsDxe/BdsEntry.c create mode 100644 MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c create mode 100644 MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h create mode 100644 MdeModulePkg/Universal/BdsDxe/Language.c create mode 100644 MdeModulePkg/Universal/BdsDxe/Language.h diff --git a/MdeModulePkg/Include/Library/PlatformBootManagerLib.h b/MdeModulePkg/Include/Library/PlatformBootManagerLib.h new file mode 100644 index 0000000000..52745032e4 --- /dev/null +++ b/MdeModulePkg/Include/Library/PlatformBootManagerLib.h @@ -0,0 +1,62 @@ +/** @file + Platform Boot Manager library definition. A platform can implement + instances to support platform-specific behavior. + +Copyright (c) 2011 - 2015, Intel Corporation. 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. + +**/ + + +#ifndef __PLATFORM_BOOT_MANAGER_LIB_H_ +#define __PLATFORM_BOOT_MANAGER_LIB_H_ +#include + +/** + Do the platform specific action before the console is connected. + + Such as: + Update console variable; + Register new Driver#### or Boot####; + Signal ReadyToLock event. +**/ +VOID +EFIAPI +PlatformBootManagerBeforeConsole ( + VOID + ); + +/** + Do the platform specific action after the console is connected. + + Such as: + Dynamically switch output mode; + Signal console ready platform customized event; + Run diagnostics like memory testing; + Connect certain devices; + Dispatch aditional option roms. +**/ +VOID +EFIAPI +PlatformBootManagerAfterConsole ( + VOID + ); + +/** + This function is called each second during the boot manager waits the timeout. + + @param TimeoutRemain The remaining timeout. +**/ +VOID +EFIAPI +PlatformBootManagerWaitCallback ( + UINT16 TimeoutRemain + ); + +#endif diff --git a/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c b/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c new file mode 100644 index 0000000000..1390e19097 --- /dev/null +++ b/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManager.c @@ -0,0 +1,67 @@ +/** @file + This file include all platform action which can be customized + by IBV/OEM. + +Copyright (c) 2012 - 2015, Intel Corporation. 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 + + +/** + Do the platform specific action before the console is connected. + + Such as: + Update console variable; + Register new Driver#### or Boot####; + Signal ReadyToLock event. +**/ +VOID +EFIAPI +PlatformBootManagerBeforeConsole ( + VOID + ) +{ + return; +} + +/** + Do the platform specific action after the console is connected. + + Such as: + Dynamically switch output mode; + Signal console ready platform customized event; + Run diagnostics like memory testing; + Connect certain devices; + Dispatch aditional option roms. +**/ +VOID +EFIAPI +PlatformBootManagerAfterConsole ( + VOID + ) +{ + return; +} + +/** + This function is called each second during the boot manager waits the timeout. + + @param TimeoutRemain The remaining timeout. +**/ +VOID +EFIAPI +PlatformBootManagerWaitCallback ( + UINT16 TimeoutRemain + ) +{ + return; +} diff --git a/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf b/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf new file mode 100644 index 0000000000..10cc3c4c67 --- /dev/null +++ b/MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf @@ -0,0 +1,36 @@ +## @file +# Include all platform action which can be customized by IBV/OEM. +# +# Copyright (c) 2012 - 2015, Intel Corporation. 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PlatformBootManagerLib + FILE_GUID = 95C097CC-8943-4038-BB8A-1C70CF2E9F3C + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformBootManagerLib|DXE_DRIVER + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + PlatformBootManager.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 6e7247016c..f854e894c3 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -108,6 +108,9 @@ ## @libraryclass Provides core boot manager functions UefiBootManagerLib|Include/Library/UefiBootManagerLib.h + ## @libraryclass Provides core boot manager functions + PlatformBootManagerLib|Include/Library/PlatformBootManagerLib.h + [Guids] ## MdeModule package token space guid # Include/Guid/MdeModulePkgTokenSpace.h diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index f937e83eb5..1573942a24 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -62,6 +62,7 @@ PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf # # Generic Modules # @@ -93,6 +94,7 @@ SmbusLib|MdePkg/Library/DxeSmbusLib/DxeSmbusLib.inf S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf CpuExceptionHandlerLib|MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf + PlatformBootManagerLib|MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf [LibraryClasses.EBC.PEIM] IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf @@ -269,7 +271,9 @@ MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf + MdeModulePkg/Library/PlatformBootManagerLibNull/PlatformBootManagerLibNull.inf + MdeModulePkg/Universal/BdsDxe/BdsDxe.inf MdeModulePkg/Universal/CapsulePei/CapsulePei.inf MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf diff --git a/MdeModulePkg/Universal/BdsDxe/Bds.h b/MdeModulePkg/Universal/BdsDxe/Bds.h new file mode 100644 index 0000000000..2171d14791 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/Bds.h @@ -0,0 +1,106 @@ +/** @file + Head file for BDS Architectural Protocol implementation + +Copyright (c) 2004 - 2015, Intel Corporation. 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. + +**/ + +#ifndef _BDS_MODULE_H_ +#define _BDS_MODULE_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + + 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 + ); + +/** + Set the variable and report the error through status code upon failure. + + @param VariableName A Null-terminated string that is the name of the vendor's variable. + Each VariableName is unique for each VendorGuid. VariableName must + contain 1 or more characters. If VariableName is an empty string, + then EFI_INVALID_PARAMETER is returned. + @param VendorGuid A unique identifier for the vendor. + @param Attributes Attributes bitmask to set for the variable. + @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, + EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero + causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is + set, then a SetVariable() call with a DataSize of zero will not cause any change to + the variable value (the timestamp associated with the variable may be updated however + even if no new data value is provided,see the description of the + EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not + be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). + @param Data The contents for the variable. + + @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as + defined by the Attributes. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the + DataSize exceeds the maximum allowed. + @retval EFI_INVALID_PARAMETER VariableName is an empty string. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + @retval EFI_WRITE_PROTECTED The variable in question is read-only. + @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted. + @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS + or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo + does NOT pass the validation check carried out by the firmware. + + @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. +**/ +EFI_STATUS +BdsDxeSetVariableAndReportStatusCodeOnError ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ); + +#endif diff --git a/MdeModulePkg/Universal/BdsDxe/BdsDxe.inf b/MdeModulePkg/Universal/BdsDxe/BdsDxe.inf new file mode 100644 index 0000000000..1d2217575b --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BdsDxe.inf @@ -0,0 +1,101 @@ +## @file +# BdsDxe module is core driver for BDS phase. +# +# When DxeCore dispatching all DXE driver, this module will produce architecture protocol +# gEfiBdsArchProtocolGuid. After DxeCore finish dispatching, DxeCore will invoke Entry +# interface of protocol gEfiBdsArchProtocolGuid, then BDS phase is entered. +# +# Copyright (c) 2008 - 2015, Intel Corporation. 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BdsDxe + FILE_GUID = 6D33944A-EC75-4855-A54D-809C75241F6C + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = BdsInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + Language.h + Bds.h + HwErrRecSupport.c + HwErrRecSupport.h + Language.c + BdsEntry.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + DevicePathLib + BaseLib + MemoryAllocationLib + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + ReportStatusCodeLib + UefiLib + BaseMemoryLib + DebugLib + UefiBootManagerLib + PlatformBootManagerLib + PcdLib + +[Guids] + gEfiGlobalVariableGuid ## SOMETIMES_PRODUCES ## Variable:L"BootNext" (The number of next boot option) + ## SOMETIMES_PRODUCES ## Variable:L"Boot####" (Boot option variable) + ## SOMETIMES_PRODUCES ## Variable:L"PlatformLang" (Platform supported languange in Rfc4646 format) + ## SOMETIMES_PRODUCES ## Variable:L"Lang" (Platform supported languange in Iso639 format) + ## SOMETIMES_PRODUCES ## Variable:L"Key####" (Hotkey option variable) + ## PRODUCES ## Variable:L"HwErrRecSupport" (The level of platform supported hardware Error Record Persistence) + ## SOMETIMES_PRODUCES ## Variable:L"BootOptionSupport" (The feature supported in boot option menu, value could be: EFI_BOOT_OPTION_SUPPORT_KEY, EFI_BOOT_OPTION_SUPPORT_APP + ## SOMETIMES_PRODUCES (not PcdUefiVariableDefaultLangDeprecate) ## Variable:L"LangCodes" (Value of PcdUefiVariableDefaultLangCodes) + ## PRODUCES ## Variable:L"PlatformLangCodes" (Value of PcdUefiVariableDefaultPlatformLangCodes) + ## PRODUCES ## Variable:L"Timeout" (The time out value in second of showing progress bar) + ## SOMETIMES_PRODUCES ## Variable:L"BootOrder" (The boot option array) + ## SOMETIMES_PRODUCES ## Variable:L"DriverOrder" (The driver order list) + ## SOMETIMES_CONSUMES ## Variable:L"ConIn" (The device path of console in device) + ## SOMETIMES_CONSUMES ## Variable:L"ConOut" (The device path of console out device) + ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" (The device path of error out device) + gConnectConInEventGuid ## SOMETIMES_CONSUMES ## Event + gEdkiiStatusCodeDataTypeVariableGuid ## SOMETIMES_CONSUMES ## GUID + +[Protocols] + gEfiBdsArchProtocolGuid ## PRODUCES + gEfiSimpleTextInputExProtocolGuid ## CONSUMES + gEdkiiVariableLockProtocolGuid ## CONSUMES + +[FeaturePcd] + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangCodes ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang ## SOMETIMES_CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLangCodes ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVendor ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareRevision ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdConInConnectOnDemand ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable ## SOMETIMES_CONSUMES + +[Depex] + TRUE diff --git a/MdeModulePkg/Universal/BdsDxe/BdsEntry.c b/MdeModulePkg/Universal/BdsDxe/BdsEntry.c new file mode 100644 index 0000000000..7eebe84021 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/BdsEntry.c @@ -0,0 +1,1246 @@ +/** @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 - 2015, Intel Corporation. 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 "HwErrRecSupport.h" + +#define SET_BOOT_OPTION_SUPPORT_KEY_COUNT(a, c) { \ + (a) = ((a) & ~EFI_BOOT_OPTION_SUPPORT_COUNT) | (((c) << LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT)) & EFI_BOOT_OPTION_SUPPORT_COUNT); \ + } + +/// +/// BDS arch protocol instance initial value. +/// +EFI_BDS_ARCH_PROTOCOL gBds = { + BdsEntry +}; + +// +// gConnectConInEvent - Event which is signaled when ConIn connection is required +// +EFI_EVENT gConnectConInEvent = NULL; + +/// +/// The read-only variables defined in UEFI Spec. +/// +CHAR16 *mReadOnlyVariables[] = { + EFI_PLATFORM_LANG_CODES_VARIABLE_NAME, + EFI_LANG_CODES_VARIABLE_NAME, + EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, + EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME, + EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME + }; + +CHAR16 mRecoveryBoot[] = L"Recovery Boot"; +/** + Event to Connect ConIn. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context, + which is implementation-dependent. + +**/ +VOID +EFIAPI +BdsDxeOnConnectConInCallBack ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // When Osloader call ReadKeyStroke to signal this event + // no driver dependency is assumed existing. So use a non-dispatch version + // + Status = EfiBootManagerConnectConsoleVariable (ConIn); + if (EFI_ERROR (Status)) { + // + // Should not enter this case, if enter, the keyboard will not work. + // May need platfrom policy to connect keyboard. + // + DEBUG ((EFI_D_WARN, "[Bds] ASSERT Connect ConIn failed!!!\n")); + } +} + +/** + + 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; + EFI_HANDLE Handle; + // + // Install protocol interface + // + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiBdsArchProtocolGuid, &gBds, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Emuerate all possible bootable medias in the following order: + 1. Removable BlockIo - The boot option only points to the removable media + device, like USB key, DVD, Floppy etc. + 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device, + like HardDisk. + 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting + SimpleFileSystem Protocol, but not supporting BlockIo + protocol. + 4. LoadFile - The boot option points to the media supporting + LoadFile protocol. + Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior + + @param BootOptionCount Return the boot option count which has been found. + + @retval Pointer to the boot option array. +**/ +EFI_BOOT_MANAGER_LOAD_OPTION * +BdsEnumerateBootOptions ( + UINTN *BootOptionCount + ) +{ + EFI_STATUS Status; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + UINT16 NonBlockNumber; + UINTN HandleCount; + EFI_HANDLE *Handles; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + UINTN Removable; + UINTN Index; + + ASSERT (BootOptionCount != NULL); + + *BootOptionCount = 0; + BootOptions = NULL; + + // + // Parse removable block io followed by fixed block io + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + + for (Removable = 0; Removable < 2; Removable++) { + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + Handles[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo + ); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Skip the logical partitions + // + if (BlkIo->Media->LogicalPartition) { + continue; + } + + // + // Skip the fixed block io then the removable block io + // + if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) { + continue; + } + + BootOptions = ReallocatePool ( + sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount), + sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1), + BootOptions + ); + ASSERT (BootOptions != NULL); + + Status = EfiBootManagerInitializeLoadOption ( + &BootOptions[(*BootOptionCount)++], + LoadOptionNumberUnassigned, + LoadOptionTypeBoot, + LOAD_OPTION_ACTIVE, + mRecoveryBoot, + DevicePathFromHandle (Handles[Index]), + NULL, + 0 + ); + ASSERT_EFI_ERROR (Status); + } + } + + if (HandleCount != 0) { + FreePool (Handles); + } + + // + // Parse simple file system not based on block io + // + NonBlockNumber = 0; + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + Handles[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo + ); + if (!EFI_ERROR (Status)) { + // + // Skip if the file system handle supports a BlkIo protocol, which we've handled in above + // + continue; + } + BootOptions = ReallocatePool ( + sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount), + sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1), + BootOptions + ); + ASSERT (BootOptions != NULL); + + Status = EfiBootManagerInitializeLoadOption ( + &BootOptions[(*BootOptionCount)++], + LoadOptionNumberUnassigned, + LoadOptionTypeBoot, + LOAD_OPTION_ACTIVE, + mRecoveryBoot, + DevicePathFromHandle (Handles[Index]), + NULL, + 0 + ); + ASSERT_EFI_ERROR (Status); + } + + if (HandleCount != 0) { + FreePool (Handles); + } + + // + // Parse load file, assuming UEFI Network boot option + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiLoadFileProtocolGuid, + NULL, + &HandleCount, + &Handles + ); + for (Index = 0; Index < HandleCount; Index++) { + + BootOptions = ReallocatePool ( + sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount), + sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1), + BootOptions + ); + ASSERT (BootOptions != NULL); + + Status = EfiBootManagerInitializeLoadOption ( + &BootOptions[(*BootOptionCount)++], + LoadOptionNumberUnassigned, + LoadOptionTypeBoot, + LOAD_OPTION_ACTIVE, + mRecoveryBoot, + DevicePathFromHandle (Handles[Index]), + NULL, + 0 + ); + ASSERT_EFI_ERROR (Status); + } + + if (HandleCount != 0) { + FreePool (Handles); + } + + return BootOptions; +} + +/** + Function waits for a given event to fire, or for an optional timeout to expire. + + @param Event The event to wait for + @param Timeout An optional timeout value in 100 ns units. + + @retval EFI_SUCCESS Event fired before Timeout expired. + @retval EFI_TIME_OUT Timout expired before Event fired.. + +**/ +EFI_STATUS +BdsWaitForSingleEvent ( + IN EFI_EVENT Event, + IN UINT64 Timeout OPTIONAL + ) +{ + UINTN Index; + EFI_STATUS Status; + EFI_EVENT TimerEvent; + EFI_EVENT WaitList[2]; + + if (Timeout != 0) { + // + // Create a timer event + // + Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); + if (!EFI_ERROR (Status)) { + // + // Set the timer event + // + gBS->SetTimer ( + TimerEvent, + TimerRelative, + Timeout + ); + + // + // Wait for the original event or the timer + // + WaitList[0] = Event; + WaitList[1] = TimerEvent; + Status = gBS->WaitForEvent (2, WaitList, &Index); + ASSERT_EFI_ERROR (Status); + gBS->CloseEvent (TimerEvent); + + // + // If the timer expired, change the return to timed out + // + if (Index == 1) { + Status = EFI_TIMEOUT; + } + } + } else { + // + // No timeout... just wait on the event + // + Status = gBS->WaitForEvent (1, &Event, &Index); + ASSERT (!EFI_ERROR (Status)); + ASSERT (Index == 0); + } + + return Status; +} + +/** + The function reads user inputs. + +**/ +VOID +BdsReadKeys ( + VOID + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + + if (PcdGetBool (PcdConInConnectOnDemand)) { + return; + } + + while (gST->ConIn != NULL) { + + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + + if (EFI_ERROR (Status)) { + // + // No more keys. + // + break; + } + } +} + +/** + The function waits for the boot manager timeout expires or hotkey is pressed. + + It calls PlatformBootManagerWaitCallback each second. + + @param HotkeyTriggered Input hotkey event. +**/ +VOID +BdsWait ( + IN EFI_EVENT HotkeyTriggered + ) +{ + EFI_STATUS Status; + UINT16 TimeoutRemain; + + DEBUG ((EFI_D_INFO, "[Bds]BdsWait ...Zzzzzzzzzzzz...\n")); + + TimeoutRemain = PcdGet16 (PcdPlatformBootTimeOut); + while (TimeoutRemain != 0) { + DEBUG ((EFI_D_INFO, "[Bds]BdsWait(%d)..Zzzz...\n", (UINTN) TimeoutRemain)); + PlatformBootManagerWaitCallback (TimeoutRemain); + + BdsReadKeys (); // BUGBUG: Only reading can signal HotkeyTriggered + // Can be removed after all keyboard drivers invoke callback in timer callback. + + if (HotkeyTriggered != NULL) { + Status = BdsWaitForSingleEvent (HotkeyTriggered, EFI_TIMER_PERIOD_SECONDS (1)); + if (!EFI_ERROR (Status)) { + break; + } + } else { + gBS->Stall (1000000); + } + + // + // 0xffff means waiting forever + // BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop + // + if (TimeoutRemain != 0xffff) { + TimeoutRemain--; + } + } + DEBUG ((EFI_D_INFO, "[Bds]Exit the waiting!\n")); +} + +/** + Attempt to boot each boot option in the BootOptions array. + + @param BootOptions Input boot option array. + @param BootOptionCount Input boot option count. + + @retval TRUE Successfully boot one of the boot options. + @retval FALSE Failed boot any of the boot options. +**/ +BOOLEAN +BootAllBootOptions ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions, + IN UINTN BootOptionCount + ) +{ + UINTN Index; + + // + // Attempt boot each boot option + // + for (Index = 0; Index < BootOptionCount; Index++) { + // + // 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 ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) { + continue; + } + + // + // Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not + // part of the normal boot processing. Boot options with reserved category values will be + // ignored by the boot manager. + // + if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT) { + continue; + } + + // + // All the driver options should have been processed since + // now boot will be performed. + // + EfiBootManagerBoot (&BootOptions[Index]); + + // + // Successful boot breaks the loop, otherwise tries next boot option + // + if (BootOptions[Index].Status == EFI_SUCCESS) { + break; + } + } + + return (BOOLEAN) (Index < BootOptionCount); +} + +/** + This function attempts to boot per the boot order specified by platform policy. + + If the boot via Boot#### returns with a status of EFI_SUCCESS the boot manager will stop + processing the BootOrder variable and present a boot manager menu to the user. If a boot via + Boot#### returns a status other than EFI_SUCCESS, the boot has failed and the next Boot#### + in the BootOrder variable will be tried until all possibilities are exhausted. + -- Chapter 3.1.1 Boot Manager Programming, the 4th paragraph +**/ +VOID +DefaultBootBehavior ( + VOID + ) +{ + UINTN BootOptionCount; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu; + + EfiBootManagerGetBootManagerMenu (&BootManagerMenu); + // + // BootManagerMenu always contains the correct information even the above function returns failure. + // + + BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); + + if (BootAllBootOptions (BootOptions, BootOptionCount)) { + // + // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI + // + if (PcdGetBool (PcdConInConnectOnDemand)) { + BdsDxeOnConnectConInCallBack (NULL, NULL); + } + + // + // Show the Boot Manager Menu after successful boot + // + EfiBootManagerBoot (&BootManagerMenu); + } else { + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); + // + // Re-scan all EFI boot options in case all the boot#### are deleted or failed to boot + // + // If no valid boot options exist, the boot manager will enumerate all removable media + // devices followed by all fixed media devices. The order within each group is undefined. + // These new default boot options are not saved to non volatile storage.The boot manger + // will then attempt toboot from each boot option. + // -- Chapter 3.3 Boot Manager Programming, the 2nd paragraph + // + EfiBootManagerConnectAll (); + BootOptions = BdsEnumerateBootOptions (&BootOptionCount); + + if (!BootAllBootOptions (BootOptions, BootOptionCount)) { + DEBUG ((EFI_D_ERROR, "[Bds]No bootable device!\n")); + EfiBootManagerBoot (&BootManagerMenu); + } + } + + EfiBootManagerFreeLoadOption (&BootManagerMenu); + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); +} + +/** + The function will go through the driver option link list, load and start + every driver the driver option device path point to. + + @param DriverOption Input driver option array. + @param DriverOptionCount Input driver option count. + +**/ +VOID +LoadDrivers ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *DriverOption, + IN UINTN DriverOptionCount + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_HANDLE ImageHandle; + EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; + BOOLEAN ReconnectAll; + + ReconnectAll = FALSE; + + // + // Process the driver option + // + for (Index = 0; Index < DriverOptionCount; Index++) { + // + // If a load option is not marked as LOAD_OPTION_ACTIVE, + // the boot manager will not automatically load the option. + // + if ((DriverOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) { + continue; + } + + // + // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT, + // then all of the EFI drivers in the system will be disconnected and + // reconnected after the last driver load option is processed. + // + if ((DriverOption[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) { + ReconnectAll = TRUE; + } + + // + // Make sure the driver path is connected. + // + EfiBootManagerConnectDevicePath (DriverOption[Index].FilePath, NULL); + + // + // Load and start the image that Driver#### describes + // + Status = gBS->LoadImage ( + FALSE, + gImageHandle, + DriverOption[Index].FilePath, + NULL, + 0, + &ImageHandle + ); + + if (!EFI_ERROR (Status)) { + gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo); + + // + // Verify whether this image is a driver, if not, + // exit it and continue to parse next load option + // + if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) { + gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL); + continue; + } + + ImageInfo->LoadOptionsSize = DriverOption[Index].OptionalDataSize; + ImageInfo->LoadOptions = DriverOption[Index].OptionalData; + // + // Before calling the image, enable the Watchdog Timer for + // the 5 Minute period + // + gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); + + DriverOption[Index].Status = gBS->StartImage (ImageHandle, &DriverOption[Index].ExitDataSize, &DriverOption[Index].ExitData); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", DriverOption[Index].Status)); + + // + // Clear the Watchdog Timer after the image returns + // + gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); + } + } + + // + // Process the LOAD_OPTION_FORCE_RECONNECT driver option + // + if (ReconnectAll) { + EfiBootManagerDisconnectAll (); + EfiBootManagerConnectAll (); + } + +} + +/** + + Validate input console variable data. + + If found the device path is not a valid device path, remove the variable. + + @param VariableName Input console variable name. + +**/ +VOID +BdsFormalizeConsoleVariable ( + IN CHAR16 *VariableName + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN VariableSize; + EFI_STATUS Status; + + GetEfiGlobalVariable2 (VariableName, (VOID **) &DevicePath, &VariableSize); + if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) { + Status = gRT->SetVariable ( + VariableName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + 0, + NULL + ); + // + // Deleting variable with current variable implementation shouldn't fail. + // + ASSERT_EFI_ERROR (Status); + } + + if (DevicePath != NULL) { + FreePool (DevicePath); + } +} + +/** + Formalize OsIndication related variables. + + For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps + Delete OsIndications variable if it is not NV/BS/RT UINT64. + + Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable. + +**/ +VOID +BdsFormalizeOSIndicationVariable ( + VOID + ) +{ + EFI_STATUS Status; + UINT64 OsIndicationSupport; + UINT64 OsIndication; + UINTN DataSize; + UINT32 Attributes; + + // + // OS indicater support variable + // + OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI; + Status = gRT->SetVariable ( + L"OsIndicationsSupported", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(UINT64), + &OsIndicationSupport + ); + // + // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail. + // + ASSERT_EFI_ERROR (Status); + + // + // If OsIndications is invalid, remove it. + // Invalid case + // 1. Data size != UINT64 + // 2. OsIndication value inconsistence + // 3. OsIndication attribute inconsistence + // + OsIndication = 0; + Attributes = 0; + DataSize = sizeof(UINT64); + Status = gRT->GetVariable ( + L"OsIndications", + &gEfiGlobalVariableGuid, + &Attributes, + &DataSize, + &OsIndication + ); + if (Status == EFI_NOT_FOUND) { + return; + } + + if ((DataSize != sizeof (OsIndication)) || + ((OsIndication & ~OsIndicationSupport) != 0) || + (Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE)) + ){ + + DEBUG ((EFI_D_ERROR, "[Bds] Unformalized OsIndications variable exists. Delete it\n")); + Status = gRT->SetVariable ( + L"OsIndications", + &gEfiGlobalVariableGuid, + 0, + 0, + NULL + ); + // + // Deleting variable with current variable implementation shouldn't fail. + // + ASSERT_EFI_ERROR(Status); + } +} + +/** + + Validate variables. + +**/ +VOID +BdsFormalizeEfiGlobalVariable ( + VOID + ) +{ + // + // Validate Console variable. + // + BdsFormalizeConsoleVariable (L"ConIn"); + BdsFormalizeConsoleVariable (L"ConOut"); + BdsFormalizeConsoleVariable (L"ErrOut"); + + // + // Validate OSIndication related variable. + // + BdsFormalizeOSIndicationVariable (); +} + +/** + + Allocate a block of memory that will contain performance data to OS. + +**/ +VOID +BdsAllocateMemoryForPerformanceData ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase; + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; + + AcpiLowMemoryBase = 0x0FFFFFFFFULL; + + // + // Allocate a block of memory that will contain performance data to OS. + // + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH), + &AcpiLowMemoryBase + ); + if (!EFI_ERROR (Status)) { + // + // Save the pointer to variable for use in S3 resume. + // + Status = BdsDxeSetVariableAndReportStatusCodeOnError ( + L"PerfDataMemAddr", + &gPerformanceProtocolGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (EFI_PHYSICAL_ADDRESS), + &AcpiLowMemoryBase + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage.\n", AcpiLowMemoryBase)); + } + // + // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists + // Still lock it even the variable cannot be saved to prevent it's set by 3rd party code. + // + Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); + if (!EFI_ERROR (Status)) { + Status = VariableLock->RequestToLock (VariableLock, L"PerfDataMemAddr", &gPerformanceProtocolGuid); + ASSERT_EFI_ERROR (Status); + } + } +} + +/** + + 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_BOOT_MANAGER_LOAD_OPTION *DriverOption; + EFI_BOOT_MANAGER_LOAD_OPTION BootOption; + UINTN DriverOptionCount; + CHAR16 *FirmwareVendor; + EFI_EVENT HotkeyTriggered; + UINT64 OsIndication; + UINTN DataSize; + EFI_STATUS Status; + UINT32 BootOptionSupport; + UINT16 BootTimeOut; + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; + UINTN Index; + UINT16 *BootNext; + CHAR16 BootNextVariableName[sizeof ("Boot####")]; + + HotkeyTriggered = NULL; + Status = EFI_SUCCESS; + + // + // Insert the performance probe + // + PERF_END (NULL, "DXE", NULL, 0); + PERF_START (NULL, "BDS", NULL, 0); + DEBUG ((EFI_D_INFO, "[Bds] Entry...\n")); + + PERF_CODE ( + BdsAllocateMemoryForPerformanceData (); + ); + + // + // Fill in FirmwareVendor and FirmwareRevision from PCDs + // + FirmwareVendor = (CHAR16 *) PcdGetPtr (PcdFirmwareVendor); + gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor); + ASSERT (gST->FirmwareVendor != NULL); + gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision); + + // + // Fixup Tasble CRC after we updated Firmware Vendor and Revision + // + gST->Hdr.CRC32 = 0; + gBS->CalculateCrc32 ((VOID *) gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32); + + // + // Validate Variable. + // + BdsFormalizeEfiGlobalVariable (); + + // + // Mark the read-only variables if the Variable Lock protocol exists + // + Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); + DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status)); + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) { + Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid); + ASSERT_EFI_ERROR (Status); + } + } + + InitializeHwErrRecSupport (); + + // + // Initialize L"Timeout" EFI global variable. + // + BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut); + if (BootTimeOut != 0xFFFF) { + // + // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification + // define same behavior between no value or 0xFFFF value for L"Timeout". + // + BdsDxeSetVariableAndReportStatusCodeOnError ( + EFI_TIME_OUT_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (UINT16), + &BootTimeOut + ); + } + + // + // Initialize L"BootOptionSupport" EFI global variable. + // Lazy-ConIn implictly disables BDS hotkey. + // + BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP; + if (!PcdGetBool (PcdConInConnectOnDemand)) { + BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY; + SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3); + } + Status = gRT->SetVariable ( + EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (BootOptionSupport), + &BootOptionSupport + ); + // + // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail. + // + ASSERT_EFI_ERROR (Status); + + // + // Cache and remove the "BootNext" NV variable. + // + GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **) &BootNext, &DataSize); + if (DataSize != sizeof (UINT16)) { + if (BootNext != NULL) { + FreePool (BootNext); + } + BootNext = NULL; + } + Status = gRT->SetVariable ( + EFI_BOOT_NEXT_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + 0, + 0, + NULL + ); + // + // Deleting NV variable shouldn't fail unless it doesn't exist. + // + ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND); + + // + // Initialize the platform language variables + // + InitializeLanguage (TRUE); + + // + // Report Status Code to indicate connecting drivers will happen + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS) + ); + + // + // Do the platform init, can be customized by OEM/IBV + // Possible things that can be done in PlatformBootManagerBeforeConsole: + // > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT + // > Register new Driver#### or Boot#### + // > Register new Key####: e.g.: F12 + // > Signal ReadyToLock event + // > Authentication action: 1. connect Auth devices; 2. Identify auto logon user. + // + PERF_START (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0); + PlatformBootManagerBeforeConsole (); + PERF_END (NULL, "PlatformBootManagerBeforeConsole", "BDS", 0); + + // + // Initialize hotkey service + // + EfiBootManagerStartHotkeyService (&HotkeyTriggered); + + // + // Load Driver Options + // + DriverOption = EfiBootManagerGetLoadOptions (&DriverOptionCount, LoadOptionTypeDriver); + LoadDrivers (DriverOption, DriverOptionCount); + EfiBootManagerFreeLoadOptions (DriverOption, DriverOptionCount); + + // + // Connect consoles + // + PERF_START (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0); + if (PcdGetBool (PcdConInConnectOnDemand)) { + EfiBootManagerConnectConsoleVariable (ConOut); + EfiBootManagerConnectConsoleVariable (ErrOut); + + // + // Initialize ConnectConIn event + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + BdsDxeOnConnectConInCallBack, + NULL, + &gConnectConInEventGuid, + &gConnectConInEvent + ); + if (EFI_ERROR (Status)) { + gConnectConInEvent = NULL; + } + } else { + EfiBootManagerConnectAllDefaultConsoles (); + } + PERF_END (NULL, "EfiBootManagerConnectAllDefaultConsoles", "BDS", 0); + + // + // Do the platform specific action after the console is ready + // Possible things that can be done in PlatformBootManagerAfterConsole: + // > Console post action: + // > Dynamically switch output mode from 100x31 to 80x25 for certain senarino + // > Signal console ready platform customized event + // > Run diagnostics like memory testing + // > Connect certain devices + // > Dispatch aditional option roms + // > Special boot: e.g.: USB boot, enter UI + // + PERF_START (NULL, "PlatformBootManagerAfterConsole", "BDS", 0); + PlatformBootManagerAfterConsole (); + PERF_END (NULL, "PlatformBootManagerAfterConsole", "BDS", 0); + + DEBUG_CODE ( + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + UINTN BootOptionCount; + UINTN Index; + + BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); + DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options=============\n")); + for (Index = 0; Index < BootOptionCount; Index++) { + DEBUG (( + EFI_D_INFO, "[Bds]Boot%04x: %s \t\t 0x%04x\n", + BootOptions[Index].OptionNumber, + BootOptions[Index].Description, + BootOptions[Index].Attributes + )); + } + DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options Finished====\n")); + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); + ); + + // + // Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot + // + DataSize = sizeof (UINT64); + Status = gRT->GetVariable ( + L"OsIndications", + &gEfiGlobalVariableGuid, + NULL, + &DataSize, + &OsIndication + ); + if (!EFI_ERROR(Status) && ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0)) { + // + // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS + // + OsIndication &= ~((UINT64) EFI_OS_INDICATIONS_BOOT_TO_FW_UI); + Status = gRT->SetVariable ( + L"OsIndications", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof(UINT64), + &OsIndication + ); + // + // Changing the content without increasing its size with current variable implementation shouldn't fail. + // + ASSERT_EFI_ERROR (Status); + + // + // Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI + // + if (PcdGetBool (PcdConInConnectOnDemand)) { + BdsDxeOnConnectConInCallBack (NULL, NULL); + } + + // + // Directly boot to Boot Manager Menu. + // + EfiBootManagerGetBootManagerMenu (&BootOption); + EfiBootManagerBoot (&BootOption); + EfiBootManagerFreeLoadOption (&BootOption); + } else { + PERF_START (NULL, "BdsWait", "BDS", 0); + BdsWait (HotkeyTriggered); + PERF_END (NULL, "BdsWait", "BDS", 0); + + // + // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback. + // + BdsReadKeys (); + + EfiBootManagerHotkeyBoot (); + } + + // + // Boot to "BootNext" + // + if (BootNext != NULL) { + UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext); + Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &BootOption); + if (!EFI_ERROR (Status)) { + EfiBootManagerBoot (&BootOption); + EfiBootManagerFreeLoadOption (&BootOption); + if (BootOption.Status == EFI_SUCCESS) { + // + // Boot to Boot Manager Menu upon EFI_SUCCESS + // + EfiBootManagerGetBootManagerMenu (&BootOption); + EfiBootManagerBoot (&BootOption); + EfiBootManagerFreeLoadOption (&BootOption); + } + } + } + + while (TRUE) { + // + // BDS select the boot device to load OS + // Try next upon boot failure + // Show Boot Manager Menu upon boot success + // + DefaultBootBehavior (); + } +} + +/** + Set the variable and report the error through status code upon failure. + + @param VariableName A Null-terminated string that is the name of the vendor's variable. + Each VariableName is unique for each VendorGuid. VariableName must + contain 1 or more characters. If VariableName is an empty string, + then EFI_INVALID_PARAMETER is returned. + @param VendorGuid A unique identifier for the vendor. + @param Attributes Attributes bitmask to set for the variable. + @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, + EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero + causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is + set, then a SetVariable() call with a DataSize of zero will not cause any change to + the variable value (the timestamp associated with the variable may be updated however + even if no new data value is provided,see the description of the + EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not + be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). + @param Data The contents for the variable. + + @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as + defined by the Attributes. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the + DataSize exceeds the maximum allowed. + @retval EFI_INVALID_PARAMETER VariableName is an empty string. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + @retval EFI_WRITE_PROTECTED The variable in question is read-only. + @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted. + @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS + or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo + does NOT pass the validation check carried out by the firmware. + + @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. +**/ +EFI_STATUS +BdsDxeSetVariableAndReportStatusCodeOnError ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + EFI_STATUS Status; + EDKII_SET_VARIABLE_STATUS *SetVariableStatus; + UINTN NameSize; + + Status = gRT->SetVariable ( + VariableName, + VendorGuid, + Attributes, + DataSize, + Data + ); + if (EFI_ERROR (Status)) { + NameSize = StrSize (VariableName); + SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize); + if (SetVariableStatus != NULL) { + CopyGuid (&SetVariableStatus->Guid, VendorGuid); + SetVariableStatus->NameSize = NameSize; + SetVariableStatus->DataSize = DataSize; + SetVariableStatus->SetStatus = Status; + SetVariableStatus->Attributes = Attributes; + CopyMem (SetVariableStatus + 1, VariableName, NameSize); + CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize); + + REPORT_STATUS_CODE_EX ( + EFI_ERROR_CODE, + PcdGet32 (PcdErrorCodeSetVariable), + 0, + NULL, + &gEdkiiStatusCodeDataTypeVariableGuid, + SetVariableStatus, + sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize + ); + + FreePool (SetVariableStatus); + } + } + + return Status; +} diff --git a/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c b/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c new file mode 100644 index 0000000000..87e39c3c8d --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.c @@ -0,0 +1,48 @@ +/** @file + Set the level of support for Hardware Error Record Persistence that is + implemented by the platform. + +Copyright (c) 2007 - 2015, Intel Corporation. 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 "HwErrRecSupport.h" + +/** + Set the HwErrRecSupport variable contains a binary UINT16 that supplies the + level of support for Hardware Error Record Persistence that is implemented + by the platform. + +**/ +VOID +InitializeHwErrRecSupport ( + VOID + ) +{ + EFI_STATUS Status; + UINT16 HardwareErrorRecordLevel; + + HardwareErrorRecordLevel = PcdGet16 (PcdHardwareErrorRecordLevel); + + if (HardwareErrorRecordLevel != 0) { + // + // If level value equal 0, no need set to 0 to variable area because UEFI specification + // define same behavior between no value or 0 value for L"HwErrRecSupport". + // + Status = gRT->SetVariable ( + L"HwErrRecSupport", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (UINT16), + &HardwareErrorRecordLevel + ); + ASSERT_EFI_ERROR(Status); + } +} diff --git a/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h b/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h new file mode 100644 index 0000000000..2ac05d5566 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/HwErrRecSupport.h @@ -0,0 +1,32 @@ +/** @file + Set the level of support for Hardware Error Record Persistence that is + implemented by the platform. + +Copyright (c) 2007 - 2015, Intel Corporation. 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. + +**/ + +#ifndef _HW_ERR_REC_SUPPORT_H_ +#define _HW_ERR_REC_SUPPORT_H_ + +#include "Bds.h" + +/** + Set the HwErrRecSupport variable contains a binary UINT16 that supplies the + level of support for Hardware Error Record Persistence that is implemented + by the platform. + +**/ +VOID +InitializeHwErrRecSupport ( + VOID + ); + +#endif diff --git a/MdeModulePkg/Universal/BdsDxe/Language.c b/MdeModulePkg/Universal/BdsDxe/Language.c new file mode 100644 index 0000000000..09127316fb --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/Language.c @@ -0,0 +1,202 @@ +/** @file + Language settings + +Copyright (c) 2004 - 2015, Intel Corporation. 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" +#define ISO_639_2_ENTRY_SIZE 3 + +/** + Check if lang is in supported language codes according to language string. + + This code is used to check if lang is in in supported language codes. It can handle + RFC4646 and ISO639 language tags. + In ISO639 language tags, take 3-characters as a delimitation to find matched string. + In RFC4646 language tags, take semicolon as a delimitation to find matched string. + + For example: + SupportedLang = "engfraengfra" + Iso639Language = TRUE + Lang = "eng", the return value is "TRUE", or + Lang = "chs", the return value is "FALSE". + Another example: + SupportedLang = "en;fr;en-US;fr-FR" + Iso639Language = FALSE + Lang = "en", the return value is "TRUE", or + Lang = "zh", the return value is "FALSE". + + @param SupportedLang Platform supported language codes. + @param Lang Configured language. + @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646. + + @retval TRUE lang is in supported language codes. + @retval FALSE lang is not in supported language codes. + +**/ +BOOLEAN +IsLangInSupportedLangCodes( + IN CHAR8 *SupportedLang, + IN CHAR8 *Lang, + IN BOOLEAN Iso639Language + ) +{ + UINTN Index; + UINTN CompareLength; + UINTN LanguageLength; + + if (Iso639Language) { + CompareLength = ISO_639_2_ENTRY_SIZE; + for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) { + if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) { + // + // Successfully find the Lang string in SupportedLang string. + // + return TRUE; + } + } + return FALSE; + } else { + // + // Compare RFC4646 language code + // + for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++); + + for (; *SupportedLang != '\0'; SupportedLang += CompareLength) { + // + // Skip ';' characters in SupportedLang + // + for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++); + // + // Determine the length of the next language code in SupportedLang + // + for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++); + + if ((CompareLength == LanguageLength) && + (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) { + // + // Successfully find the Lang string in SupportedLang string. + // + return TRUE; + } + } + return FALSE; + } +} + +/** + Initialize Lang or PlatformLang variable, if Lang or PlatformLang variable is not found, + or it has been set to an unsupported value(not one of platform supported language codes), + set the default language code to it. + + @param LangName Language name, L"Lang" or L"PlatformLang". + @param SupportedLang Platform supported language codes. + @param DefaultLang Default language code. + @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646, + TRUE for L"Lang" LangName or FALSE for L"PlatformLang" LangName. + +**/ +VOID +InitializeLangVariable ( + IN CHAR16 *LangName, + IN CHAR8 *SupportedLang, + IN CHAR8 *DefaultLang, + IN BOOLEAN Iso639Language + ) +{ + CHAR8 *Lang; + + // + // Find current Lang or PlatformLang from EFI Variable. + // + GetEfiGlobalVariable2 (LangName, (VOID **) &Lang, NULL); + + // + // If Lang or PlatformLang variable is not found, + // or it has been set to an unsupported value(not one of the supported language codes), + // set the default language code to it. + // + if ((Lang == NULL) || !IsLangInSupportedLangCodes (SupportedLang, Lang, Iso639Language)) { + // + // The default language code should be one of the supported language codes. + // + ASSERT (IsLangInSupportedLangCodes (SupportedLang, DefaultLang, Iso639Language)); + BdsDxeSetVariableAndReportStatusCodeOnError ( + LangName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + AsciiStrSize (DefaultLang), + DefaultLang + ); + } + + if (Lang != NULL) { + FreePool (Lang); + } +} + +/** + Determine the current language that will be used + based on language related EFI Variables. + + @param LangCodesSettingRequired - If required to set LangCodes variable + +**/ +VOID +InitializeLanguage ( + BOOLEAN LangCodesSettingRequired + ) +{ + EFI_STATUS Status; + CHAR8 *LangCodes; + CHAR8 *PlatformLangCodes; + + LangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLangCodes); + PlatformLangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes); + if (LangCodesSettingRequired) { + if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) { + // + // UEFI 2.1 depricated this variable so we support turning it off + // + Status = gRT->SetVariable ( + L"LangCodes", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + AsciiStrSize (LangCodes), + LangCodes + ); + // + // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail. + // + ASSERT_EFI_ERROR(Status); + } + + Status = gRT->SetVariable ( + L"PlatformLangCodes", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + AsciiStrSize (PlatformLangCodes), + PlatformLangCodes + ); + // + // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail. + // + ASSERT_EFI_ERROR(Status); + } + + if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) { + // + // UEFI 2.1 depricated this variable so we support turning it off + // + InitializeLangVariable (L"Lang", LangCodes, (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultLang), TRUE); + } + InitializeLangVariable (L"PlatformLang", PlatformLangCodes, (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang), FALSE); +} diff --git a/MdeModulePkg/Universal/BdsDxe/Language.h b/MdeModulePkg/Universal/BdsDxe/Language.h new file mode 100644 index 0000000000..3d5f34f561 --- /dev/null +++ b/MdeModulePkg/Universal/BdsDxe/Language.h @@ -0,0 +1,30 @@ +/** @file + Language setting + +Copyright (c) 2004 - 2015, Intel Corporation. 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. + +**/ + +#ifndef _LANGUAGE_H_ +#define _LANGUAGE_H_ + +/** + Determine the current language that will be used + based on language related EFI Variables. + + @param LangCodesSettingRequired If required to set LangCode variable + +**/ +VOID +InitializeLanguage ( + BOOLEAN LangCodesSettingRequired + ); + +#endif // _LANGUAGE_H_ -- 2.39.2