-/** @file
-*
-* Copyright (c) 2011, ARM Limited. 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 "BdsInternal.h"
-
-#include <Library/PcdLib.h>
-#include <Library/PerformanceLib.h>
-
-#include <Protocol/Bds.h>
-
-#define EFI_SET_TIMER_TO_SECOND 10000000
-
-EFI_HANDLE mImageHandle;
-
-STATIC
-EFI_STATUS
-GetConsoleDevicePathFromVariable (
- IN CHAR16* ConsoleVarName,
- IN CHAR16* DefaultConsolePaths,
- OUT EFI_DEVICE_PATH** DevicePaths
- )
-{
- EFI_STATUS Status;
- UINTN Size;
- EFI_DEVICE_PATH_PROTOCOL* DevicePathInstances;
- EFI_DEVICE_PATH_PROTOCOL* DevicePathInstance;
- CHAR16* DevicePathStr;
- CHAR16* NextDevicePathStr;
- EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
-
- Status = GetEnvironmentVariable (ConsoleVarName, NULL, NULL, (VOID**)&DevicePathInstances);
- if (EFI_ERROR(Status)) {
- Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
- ASSERT_EFI_ERROR(Status);
-
- DevicePathInstances = NULL;
-
- // Extract the Device Path instances from the multi-device path string
- while ((DefaultConsolePaths != NULL) && (DefaultConsolePaths[0] != L'\0')) {
- NextDevicePathStr = StrStr (DefaultConsolePaths, L";");
- if (NextDevicePathStr == NULL) {
- DevicePathStr = DefaultConsolePaths;
- DefaultConsolePaths = NULL;
- } else {
- DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DefaultConsolePaths + 1) * sizeof(CHAR16), DefaultConsolePaths);
- *(DevicePathStr + (NextDevicePathStr - DefaultConsolePaths)) = L'\0';
- DefaultConsolePaths = NextDevicePathStr;
- if (DefaultConsolePaths[0] == L';') {
- DefaultConsolePaths++;
- }
- }
-
- DevicePathInstance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);
- ASSERT(DevicePathInstance != NULL);
- DevicePathInstances = AppendDevicePathInstance (DevicePathInstances, DevicePathInstance);
-
- if (NextDevicePathStr != NULL) {
- FreePool (DevicePathStr);
- }
- FreePool (DevicePathInstance);
- }
-
- // Set the environment variable with this device path multi-instances
- Size = GetDevicePathSize (DevicePathInstances);
- if (Size > 0) {
- Status = gRT->SetVariable (
- ConsoleVarName,
- &gEfiGlobalVariableGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- Size,
- DevicePathInstances
- );
- } else {
- Status = EFI_INVALID_PARAMETER;
- }
- }
-
- if (!EFI_ERROR(Status)) {
- *DevicePaths = DevicePathInstances;
- }
- return EFI_SUCCESS;
-}
-
-STATIC
-EFI_STATUS
-InitializeConsolePipe (
- IN EFI_DEVICE_PATH *ConsoleDevicePaths,
- IN EFI_GUID *Protocol,
- OUT EFI_HANDLE *Handle,
- OUT VOID* *Interface
- )
-{
- EFI_STATUS Status;
- UINTN Size;
- UINTN NoHandles;
- EFI_HANDLE *Buffer;
- EFI_DEVICE_PATH_PROTOCOL* DevicePath;
-
- // Connect all the Device Path Consoles
- do {
- DevicePath = GetNextDevicePathInstance (&ConsoleDevicePaths, &Size);
-
- Status = BdsConnectDevicePath (DevicePath, Handle, NULL);
- DEBUG_CODE_BEGIN();
- if (EFI_ERROR(Status)) {
- // We convert back to the text representation of the device Path
- EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
- CHAR16* DevicePathTxt;
- EFI_STATUS Status;
-
- Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
- if (!EFI_ERROR(Status)) {
- DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePath, TRUE, TRUE);
-
- DEBUG((EFI_D_ERROR,"Fail to start the console with the Device Path '%s'. (Error '%r')\n", DevicePathTxt, Status));
-
- FreePool (DevicePathTxt);
- }
- }
- DEBUG_CODE_END();
-
- // If the console splitter driver is not supported by the platform then use the first Device Path
- // instance for the console interface.
- if (!EFI_ERROR(Status) && (*Interface == NULL)) {
- Status = gBS->HandleProtocol (*Handle, Protocol, Interface);
- }
- } while (ConsoleDevicePaths != NULL);
-
- // No Device Path has been defined for this console interface. We take the first protocol implementation
- if (*Interface == NULL) {
- Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);
- if (EFI_ERROR (Status)) {
- BdsConnectAllDrivers();
- Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);
- }
-
- if (!EFI_ERROR(Status)) {
- *Handle = Buffer[0];
- Status = gBS->HandleProtocol (*Handle, Protocol, Interface);
- ASSERT_EFI_ERROR(Status);
- }
- FreePool (Buffer);
- } else {
- Status = EFI_SUCCESS;
- }
-
- return Status;
-}
-
-EFI_STATUS
-InitializeConsole (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH* ConOutDevicePaths;
- EFI_DEVICE_PATH* ConInDevicePaths;
- EFI_DEVICE_PATH* ConErrDevicePaths;
-
- // By getting the Console Device Paths from the environment variables before initializing the console pipe, we
- // create the 3 environment variables (ConIn, ConOut, ConErr) that allows to initialize all the console interface
- // of newly installed console drivers
- Status = GetConsoleDevicePathFromVariable (L"ConOut", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths),&ConOutDevicePaths);
- ASSERT_EFI_ERROR (Status);
- Status = GetConsoleDevicePathFromVariable (L"ConIn", (CHAR16*)PcdGetPtr(PcdDefaultConInPaths),&ConInDevicePaths);
- ASSERT_EFI_ERROR (Status);
- Status = GetConsoleDevicePathFromVariable (L"ConErr", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths),&ConErrDevicePaths);
- ASSERT_EFI_ERROR (Status);
-
- // Initialize the Consoles
- Status = InitializeConsolePipe (ConOutDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **)&gST->ConOut);
- ASSERT_EFI_ERROR (Status);
- Status = InitializeConsolePipe (ConInDevicePaths, &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **)&gST->ConIn);
- ASSERT_EFI_ERROR (Status);
- Status = InitializeConsolePipe (ConErrDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **)&gST->StdErr);
- if (EFI_ERROR(Status)) {
- // In case of error, we reuse the console output for the error output
- gST->StandardErrorHandle = gST->ConsoleOutHandle;
- gST->StdErr = gST->ConOut;
- }
-
- return EFI_SUCCESS;
-}
-
-EFI_STATUS
-DefineDefaultBootEntries (
- VOID
- )
-{
- BDS_LOAD_OPTION* BdsLoadOption;
- UINTN Size;
- EFI_STATUS Status;
- EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol;
- EFI_DEVICE_PATH* BootDevicePath;
-
- //
- // If Boot Order does not exist then create a default entry
- //
- Size = 0;
- Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &Size, NULL);
- if (Status == EFI_NOT_FOUND) {
- if ((PcdGetPtr(PcdDefaultBootDevicePath) == NULL) || (StrLen ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath)) == 0)) {
- return EFI_UNSUPPORTED;
- }
-
- Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
- if (EFI_ERROR(Status)) {
- // You must provide an implementation of DevicePathFromTextProtocol in your firmware (eg: DevicePathDxe)
- DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathFromTextProtocol\n"));
- return Status;
- }
- BootDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath));
-
- DEBUG_CODE_BEGIN();
- // We convert back to the text representation of the device Path to see if the initial text is correct
- EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
- CHAR16* DevicePathTxt;
-
- Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
- ASSERT_EFI_ERROR(Status);
- DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootDevicePath, TRUE, TRUE);
-
- ASSERT (StrCmp ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath), DevicePathTxt) == 0);
-
- FreePool (DevicePathTxt);
- DEBUG_CODE_END();
-
- // Create the entry is the Default values are correct
- if (BootDevicePath != NULL) {
- BootOptionCreate (LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,
- (CHAR16*)PcdGetPtr(PcdDefaultBootDescription),
- BootDevicePath,
- (BDS_LOADER_TYPE)PcdGet32 (PcdDefaultBootType),
- (CHAR8*)PcdGetPtr(PcdDefaultBootArgument),
- &BdsLoadOption
- );
- FreePool (BdsLoadOption);
- } else {
- Status = EFI_UNSUPPORTED;
- }
- }
-
- return EFI_SUCCESS;
-}
-
-EFI_STATUS
-StartDefaultBootOnTimeout (
- VOID
- )
-{
- UINTN Size;
- UINT16 Timeout;
- UINT16 *TimeoutPtr;
- EFI_EVENT WaitList[2];
- UINTN WaitIndex;
- UINT16 *BootOrder;
- UINTN BootOrderSize;
- UINTN Index;
- CHAR16 BootVariableName[9];
- EFI_STATUS Status;
-
- Size = sizeof(UINT16);
- Timeout = (UINT16)PcdGet16 (PcdPlatformBootTimeOut);
- TimeoutPtr = &Timeout;
- GetEnvironmentVariable (L"Timeout", &Timeout, &Size, (VOID**)&TimeoutPtr);
-
- if (Timeout != 0xFFFF) {
- if (Timeout > 0) {
- // Create the waiting events (keystroke and 1sec timer)
- gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &WaitList[0]);
- gBS->SetTimer (WaitList[0], TimerPeriodic, EFI_SET_TIMER_TO_SECOND);
- WaitList[1] = gST->ConIn->WaitForKey;
-
- // Start the timer
- WaitIndex = 0;
- Print(L"The default boot selection will start in ");
- while ((Timeout > 0) && (WaitIndex == 0)) {
- Print(L"%3d seconds",Timeout);
- gBS->WaitForEvent (2, WaitList, &WaitIndex);
- if (WaitIndex == 0) {
- Print(L"\b\b\b\b\b\b\b\b\b\b\b");
- Timeout--;
- }
- }
- gBS->CloseEvent (WaitList[0]);
- Print(L"\n\r");
- }
-
- // In case of Timeout we start the default boot selection
- if (Timeout == 0) {
- // Get the Boot Option Order from the environment variable (a default value should have been created)
- GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
-
- for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
- UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOrder[Index]);
- Status = BdsStartBootOption (BootVariableName);
- if(!EFI_ERROR(Status)){
- // Boot option returned successfully, hence don't need to start next boot option
- break;
- }
- // In case of success, we should not return from this call.
- }
- }
- }
- return EFI_SUCCESS;
-}
-
-/**
- This function uses policy data from the platform to determine what operating
- system or system utility should be loaded and invoked. This function call
- also optionally make the use of user input to determine the operating system
- or system utility to be loaded and invoked. When the DXE Core has dispatched
- all the drivers on the dispatch queue, this function is called. This
- function will attempt to connect the boot devices required to load and invoke
- the selected operating system or system utility. During this process,
- additional firmware volumes may be discovered that may contain addition DXE
- drivers that can be dispatched by the DXE Core. If a boot device cannot be
- fully connected, this function calls the DXE Service Dispatch() to allow the
- DXE drivers from any newly discovered firmware volumes to be dispatched.
- Then the boot device connection can be attempted again. If the same boot
- device connection operation fails twice in a row, then that boot device has
- failed, and should be skipped. This function should never return.
-
- @param This The EFI_BDS_ARCH_PROTOCOL instance.
-
- @return None.
-
-**/
-VOID
-EFIAPI
-BdsEntry (
- IN EFI_BDS_ARCH_PROTOCOL *This
- )
-{
- UINTN Size;
- EFI_STATUS Status;
-
- PERF_END (NULL, "DXE", NULL, 0);
-
- //
- // Declare the Firmware Vendor
- //
- if (FixedPcdGetPtr(PcdFirmwareVendor) != NULL) {
- Size = 0x100;
- gST->FirmwareVendor = AllocateRuntimePool (Size);
- ASSERT (gST->FirmwareVendor != NULL);
- UnicodeSPrint (gST->FirmwareVendor, Size, L"%a EFI %a %a", PcdGetPtr(PcdFirmwareVendor), __DATE__, __TIME__);
- }
-
- // If BootNext environment variable is defined then we just load it !
- Status = BdsStartBootOption (L"BootNext");
- if (Status != EFI_NOT_FOUND) {
- // BootNext has not been succeeded launched
- if (EFI_ERROR(Status)) {
- Print(L"Fail to start BootNext.\n");
- }
-
- // Delete the BootNext environment variable
- gRT->SetVariable (L"BootNext", &gEfiGlobalVariableGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
- 0, NULL);
- }
-
- // If Boot Order does not exist then create a default entry
- DefineDefaultBootEntries ();
-
- // Now we need to setup the EFI System Table with information about the console devices.
- InitializeConsole ();
-
- // Timer before initiating the default boot selection
- StartDefaultBootOnTimeout ();
-
- // Start the Boot Menu
- Status = BootMenuMain ();
- ASSERT_EFI_ERROR (Status);
-
-}
-
-EFI_BDS_ARCH_PROTOCOL gBdsProtocol = {
- BdsEntry,
-};
-
-EFI_STATUS
-EFIAPI
-BdsInitialize (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- mImageHandle = ImageHandle;
-
- Status = gBS->InstallMultipleProtocolInterfaces (
- &ImageHandle,
- &gEfiBdsArchProtocolGuid, &gBdsProtocol,
- NULL
- );
- ASSERT_EFI_ERROR (Status);
-
- return Status;
-}
+/** @file\r
+*\r
+* Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+*\r
+* 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
+**/\r
+\r
+#include "BdsInternal.h"\r
+\r
+#include <Library/PcdLib.h>\r
+#include <Library/PerformanceLib.h>\r
+\r
+#include <Protocol/Bds.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+\r
+#define EFI_SET_TIMER_TO_SECOND 10000000\r
+\r
+STATIC\r
+EFI_STATUS\r
+GetConsoleDevicePathFromVariable (\r
+ IN CHAR16* ConsoleVarName,\r
+ IN CHAR16* DefaultConsolePaths,\r
+ OUT EFI_DEVICE_PATH** DevicePaths\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+ EFI_DEVICE_PATH_PROTOCOL* DevicePathInstances;\r
+ EFI_DEVICE_PATH_PROTOCOL* DevicePathInstance;\r
+ CHAR16* DevicePathStr;\r
+ CHAR16* NextDevicePathStr;\r
+ EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;\r
+\r
+ Status = GetGlobalEnvironmentVariable (ConsoleVarName, NULL, NULL, (VOID**)&DevicePathInstances);\r
+ if (EFI_ERROR(Status)) {\r
+ // In case no default console device path has been defined we assume a driver handles the console (eg: SimpleTextInOutSerial)\r
+ if ((DefaultConsolePaths == NULL) || (DefaultConsolePaths[0] == L'\0')) {\r
+ *DevicePaths = NULL;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ DevicePathInstances = NULL;\r
+\r
+ // Extract the Device Path instances from the multi-device path string\r
+ while ((DefaultConsolePaths != NULL) && (DefaultConsolePaths[0] != L'\0')) {\r
+ NextDevicePathStr = StrStr (DefaultConsolePaths, L";");\r
+ if (NextDevicePathStr == NULL) {\r
+ DevicePathStr = DefaultConsolePaths;\r
+ DefaultConsolePaths = NULL;\r
+ } else {\r
+ DevicePathStr = (CHAR16*)AllocateCopyPool ((NextDevicePathStr - DefaultConsolePaths + 1) * sizeof(CHAR16), DefaultConsolePaths);\r
+ *(DevicePathStr + (NextDevicePathStr - DefaultConsolePaths)) = L'\0';\r
+ DefaultConsolePaths = NextDevicePathStr;\r
+ if (DefaultConsolePaths[0] == L';') {\r
+ DefaultConsolePaths++;\r
+ }\r
+ }\r
+\r
+ DevicePathInstance = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathStr);\r
+ ASSERT(DevicePathInstance != NULL);\r
+ DevicePathInstances = AppendDevicePathInstance (DevicePathInstances, DevicePathInstance);\r
+\r
+ if (NextDevicePathStr != NULL) {\r
+ FreePool (DevicePathStr);\r
+ }\r
+ FreePool (DevicePathInstance);\r
+ }\r
+\r
+ // Set the environment variable with this device path multi-instances\r
+ Size = GetDevicePathSize (DevicePathInstances);\r
+ if (Size > 0) {\r
+ gRT->SetVariable (\r
+ ConsoleVarName,\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ Size,\r
+ DevicePathInstances\r
+ );\r
+ } else {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ *DevicePaths = DevicePathInstances;\r
+ }\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+InitializeConsolePipe (\r
+ IN EFI_DEVICE_PATH *ConsoleDevicePaths,\r
+ IN EFI_GUID *Protocol,\r
+ OUT EFI_HANDLE *Handle,\r
+ OUT VOID* *Interface\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+ UINTN NoHandles;\r
+ EFI_HANDLE *Buffer;\r
+ EFI_DEVICE_PATH_PROTOCOL* DevicePath;\r
+\r
+ // Connect all the Device Path Consoles\r
+ while (ConsoleDevicePaths != NULL) {\r
+ DevicePath = GetNextDevicePathInstance (&ConsoleDevicePaths, &Size);\r
+\r
+ Status = BdsConnectDevicePath (DevicePath, Handle, NULL);\r
+ DEBUG_CODE_BEGIN();\r
+ if (EFI_ERROR(Status)) {\r
+ // We convert back to the text representation of the device Path\r
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
+ CHAR16* DevicePathTxt;\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
+ if (!EFI_ERROR(Status)) {\r
+ DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePath, TRUE, TRUE);\r
+\r
+ DEBUG((EFI_D_ERROR,"Fail to start the console with the Device Path '%s'. (Error '%r')\n", DevicePathTxt, Status));\r
+\r
+ FreePool (DevicePathTxt);\r
+ }\r
+ }\r
+ DEBUG_CODE_END();\r
+\r
+ // If the console splitter driver is not supported by the platform then use the first Device Path\r
+ // instance for the console interface.\r
+ if (!EFI_ERROR(Status) && (*Interface == NULL)) {\r
+ Status = gBS->HandleProtocol (*Handle, Protocol, Interface);\r
+ }\r
+ }\r
+\r
+ // No Device Path has been defined for this console interface. We take the first protocol implementation\r
+ if (*Interface == NULL) {\r
+ Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ BdsConnectAllDrivers();\r
+ Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer);\r
+ }\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ *Handle = Buffer[0];\r
+ Status = gBS->HandleProtocol (*Handle, Protocol, Interface);\r
+ ASSERT_EFI_ERROR(Status);\r
+ FreePool (Buffer);\r
+ }\r
+ } else {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+InitializeConsole (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH* ConOutDevicePaths;\r
+ EFI_DEVICE_PATH* ConInDevicePaths;\r
+ EFI_DEVICE_PATH* ConErrDevicePaths;\r
+\r
+ // By getting the Console Device Paths from the environment variables before initializing the console pipe, we\r
+ // create the 3 environment variables (ConIn, ConOut, ConErr) that allows to initialize all the console interface\r
+ // of newly installed console drivers\r
+ Status = GetConsoleDevicePathFromVariable (L"ConOut", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths), &ConOutDevicePaths);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = GetConsoleDevicePathFromVariable (L"ConIn", (CHAR16*)PcdGetPtr(PcdDefaultConInPaths), &ConInDevicePaths);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = GetConsoleDevicePathFromVariable (L"ErrOut", (CHAR16*)PcdGetPtr(PcdDefaultConOutPaths), &ConErrDevicePaths);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ // Initialize the Consoles\r
+ Status = InitializeConsolePipe (ConOutDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **)&gST->ConOut);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = InitializeConsolePipe (ConInDevicePaths, &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **)&gST->ConIn);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = InitializeConsolePipe (ConErrDevicePaths, &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **)&gST->StdErr);\r
+ if (EFI_ERROR(Status)) {\r
+ // In case of error, we reuse the console output for the error output\r
+ gST->StandardErrorHandle = gST->ConsoleOutHandle;\r
+ gST->StdErr = gST->ConOut;\r
+ }\r
+\r
+ // Free Memory allocated for reading the UEFI Variables\r
+ if (ConOutDevicePaths) {\r
+ FreePool (ConOutDevicePaths);\r
+ }\r
+ if (ConInDevicePaths) {\r
+ FreePool (ConInDevicePaths);\r
+ }\r
+ if (ConErrDevicePaths) {\r
+ FreePool (ConErrDevicePaths);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DefineDefaultBootEntries (\r
+ VOID\r
+ )\r
+{\r
+ BDS_LOAD_OPTION* BdsLoadOption;\r
+ UINTN Size;\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol;\r
+ EFI_DEVICE_PATH* BootDevicePath;\r
+ UINTN CmdLineSize;\r
+ UINTN CmdLineAsciiSize;\r
+ CHAR16* DefaultBootArgument;\r
+ CHAR8* AsciiDefaultBootArgument;\r
+\r
+ //\r
+ // If Boot Order does not exist then create a default entry\r
+ //\r
+ Size = 0;\r
+ Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &Size, NULL);\r
+ if (Status == EFI_NOT_FOUND) {\r
+ if ((PcdGetPtr(PcdDefaultBootDevicePath) == NULL) || (StrLen ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath)) == 0)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);\r
+ if (EFI_ERROR(Status)) {\r
+ // You must provide an implementation of DevicePathFromTextProtocol in your firmware (eg: DevicePathDxe)\r
+ DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathFromTextProtocol\n"));\r
+ return Status;\r
+ }\r
+ BootDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdDefaultBootDevicePath));\r
+\r
+ DEBUG_CODE_BEGIN();\r
+ // We convert back to the text representation of the device Path to see if the initial text is correct\r
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
+ CHAR16* DevicePathTxt;\r
+\r
+ Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
+ ASSERT_EFI_ERROR(Status);\r
+ DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootDevicePath, TRUE, TRUE);\r
+\r
+ if (StrCmp ((CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath), DevicePathTxt) != 0) {\r
+ DEBUG ((EFI_D_ERROR, "Device Path given: '%s' Device Path expected: '%s'\n",\r
+ (CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath), DevicePathTxt));\r
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ FreePool (DevicePathTxt);\r
+ DEBUG_CODE_END();\r
+\r
+ // Create the entry is the Default values are correct\r
+ if (BootDevicePath != NULL) {\r
+ // We do not support NULL pointer\r
+ ASSERT (PcdGetPtr (PcdDefaultBootArgument) != NULL);\r
+\r
+ //\r
+ // Logic to handle ASCII or Unicode default parameters\r
+ //\r
+ if (*(CHAR8*)PcdGetPtr (PcdDefaultBootArgument) == '\0') {\r
+ CmdLineSize = 0;\r
+ CmdLineAsciiSize = 0;\r
+ DefaultBootArgument = NULL;\r
+ AsciiDefaultBootArgument = NULL;\r
+ } else if (IsUnicodeString ((CHAR16*)PcdGetPtr (PcdDefaultBootArgument))) {\r
+ // The command line is a Unicode string\r
+ DefaultBootArgument = (CHAR16*)PcdGetPtr (PcdDefaultBootArgument);\r
+ CmdLineSize = StrSize (DefaultBootArgument);\r
+\r
+ // Initialize ASCII variables\r
+ CmdLineAsciiSize = CmdLineSize / 2;\r
+ AsciiDefaultBootArgument = AllocatePool (CmdLineAsciiSize);\r
+ if (AsciiDefaultBootArgument == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ UnicodeStrToAsciiStr ((CHAR16*)PcdGetPtr (PcdDefaultBootArgument), AsciiDefaultBootArgument);\r
+ } else {\r
+ // The command line is a ASCII string\r
+ AsciiDefaultBootArgument = (CHAR8*)PcdGetPtr (PcdDefaultBootArgument);\r
+ CmdLineAsciiSize = AsciiStrSize (AsciiDefaultBootArgument);\r
+\r
+ // Initialize ASCII variables\r
+ CmdLineSize = CmdLineAsciiSize * 2;\r
+ DefaultBootArgument = AllocatePool (CmdLineSize);\r
+ if (DefaultBootArgument == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ AsciiStrToUnicodeStr (AsciiDefaultBootArgument, DefaultBootArgument);\r
+ }\r
+\r
+ BootOptionCreate (LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,\r
+ (CHAR16*)PcdGetPtr (PcdDefaultBootDescription),\r
+ BootDevicePath,\r
+ (UINT8 *)DefaultBootArgument, // OptionalData\r
+ CmdLineSize, // OptionalDataSize\r
+ &BdsLoadOption\r
+ );\r
+ FreePool (BdsLoadOption);\r
+\r
+ if (DefaultBootArgument == (CHAR16*)PcdGetPtr (PcdDefaultBootArgument)) {\r
+ FreePool (AsciiDefaultBootArgument);\r
+ } else if (DefaultBootArgument != NULL) {\r
+ FreePool (DefaultBootArgument);\r
+ }\r
+ } else {\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+StartDefaultBootOnTimeout (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Size;\r
+ UINT16 Timeout;\r
+ UINT16 *TimeoutPtr;\r
+ EFI_EVENT WaitList[2];\r
+ UINTN WaitIndex;\r
+ UINT16 *BootOrder;\r
+ UINTN BootOrderSize;\r
+ UINTN Index;\r
+ CHAR16 BootVariableName[9];\r
+ EFI_STATUS Status;\r
+ EFI_INPUT_KEY Key;\r
+\r
+ Size = sizeof(UINT16);\r
+ Timeout = (UINT16)PcdGet16 (PcdPlatformBootTimeOut);\r
+ Status = GetGlobalEnvironmentVariable (L"Timeout", &Timeout, &Size, (VOID**)&TimeoutPtr);\r
+ if (!EFI_ERROR (Status)) {\r
+ Timeout = *TimeoutPtr;\r
+ FreePool (TimeoutPtr);\r
+ }\r
+\r
+ if (Timeout != 0xFFFF) {\r
+ if (Timeout > 0) {\r
+ // Create the waiting events (keystroke and 1sec timer)\r
+ gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &WaitList[0]);\r
+ gBS->SetTimer (WaitList[0], TimerPeriodic, EFI_SET_TIMER_TO_SECOND);\r
+ WaitList[1] = gST->ConIn->WaitForKey;\r
+\r
+ // Start the timer\r
+ WaitIndex = 0;\r
+ Print(L"The default boot selection will start in ");\r
+ while ((Timeout > 0) && (WaitIndex == 0)) {\r
+ Print(L"%3d seconds",Timeout);\r
+ gBS->WaitForEvent (2, WaitList, &WaitIndex);\r
+ if (WaitIndex == 0) {\r
+ Print(L"\b\b\b\b\b\b\b\b\b\b\b");\r
+ Timeout--;\r
+ }\r
+ }\r
+ // Discard key in the buffer\r
+ do {\r
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+ } while(!EFI_ERROR(Status));\r
+ gBS->CloseEvent (WaitList[0]);\r
+ Print(L"\n\r");\r
+ }\r
+\r
+ // In case of Timeout we start the default boot selection\r
+ if (Timeout == 0) {\r
+ // Get the Boot Option Order from the environment variable (a default value should have been created)\r
+ GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);\r
+\r
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
+ UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOrder[Index]);\r
+ Status = BdsStartBootOption (BootVariableName);\r
+ if(!EFI_ERROR(Status)){\r
+ // Boot option returned successfully, hence don't need to start next boot option\r
+ break;\r
+ }\r
+ // In case of success, we should not return from this call.\r
+ }\r
+ FreePool (BootOrder);\r
+ }\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ An empty function to pass error checking of CreateEventEx ().\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+ @param Context Pointer to the notification function's context,\r
+ which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EmptyCallbackFunction (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ return;\r
+}\r
+\r
+/**\r
+ This function uses policy data from the platform to determine what operating\r
+ system or system utility should be loaded and invoked. This function call\r
+ also optionally make the use of user input to determine the operating system\r
+ or system utility to be loaded and invoked. When the DXE Core has dispatched\r
+ all the drivers on the dispatch queue, this function is called. This\r
+ function will attempt to connect the boot devices required to load and invoke\r
+ the selected operating system or system utility. During this process,\r
+ additional firmware volumes may be discovered that may contain addition DXE\r
+ drivers that can be dispatched by the DXE Core. If a boot device cannot be\r
+ fully connected, this function calls the DXE Service Dispatch() to allow the\r
+ DXE drivers from any newly discovered firmware volumes to be dispatched.\r
+ Then the boot device connection can be attempted again. If the same boot\r
+ device connection operation fails twice in a row, then that boot device has\r
+ failed, and should be skipped. This function should never return.\r
+\r
+ @param This The EFI_BDS_ARCH_PROTOCOL instance.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BdsEntry (\r
+ IN EFI_BDS_ARCH_PROTOCOL *This\r
+ )\r
+{\r
+ UINTN Size;\r
+ EFI_STATUS Status;\r
+ UINT16 *BootNext;\r
+ UINTN BootNextSize;\r
+ CHAR16 BootVariableName[9];\r
+ EFI_EVENT EndOfDxeEvent;\r
+\r
+ //\r
+ // Signal EndOfDxe PI Event\r
+ //\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ EmptyCallbackFunction,\r
+ NULL,\r
+ &gEfiEndOfDxeEventGroupGuid,\r
+ &EndOfDxeEvent\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->SignalEvent (EndOfDxeEvent);\r
+ }\r
+\r
+ PERF_END (NULL, "DXE", NULL, 0);\r
+\r
+ //\r
+ // Declare the Firmware Vendor\r
+ //\r
+ if (FixedPcdGetPtr(PcdFirmwareVendor) != NULL) {\r
+ Size = 0x100;\r
+ gST->FirmwareVendor = AllocateRuntimePool (Size);\r
+ ASSERT (gST->FirmwareVendor != NULL);\r
+ UnicodeSPrint (gST->FirmwareVendor, Size, L"%a EFI %a %a", PcdGetPtr(PcdFirmwareVendor), __DATE__, __TIME__);\r
+ }\r
+\r
+ //\r
+ // Fixup Table CRC after we updated Firmware Vendor\r
+ //\r
+ gST->Hdr.CRC32 = 0;\r
+ Status = gBS->CalculateCrc32 ((VOID*)gST, gST->Hdr.HeaderSize, &gST->Hdr.CRC32);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ // Now we need to setup the EFI System Table with information about the console devices.\r
+ InitializeConsole ();\r
+\r
+ // If BootNext environment variable is defined then we just load it !\r
+ BootNextSize = sizeof(UINT16);\r
+ Status = GetGlobalEnvironmentVariable (L"BootNext", NULL, &BootNextSize, (VOID**)&BootNext);\r
+ if (!EFI_ERROR(Status)) {\r
+ ASSERT(BootNextSize == sizeof(UINT16));\r
+\r
+ // Generate the requested Boot Entry variable name\r
+ UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", *BootNext);\r
+\r
+ // Set BootCurrent variable\r
+ gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ BootNextSize, BootNext);\r
+\r
+ FreePool (BootNext);\r
+\r
+ // Start the requested Boot Entry\r
+ Status = BdsStartBootOption (BootVariableName);\r
+ if (Status != EFI_NOT_FOUND) {\r
+ // BootNext has not been succeeded launched\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"Fail to start BootNext.\n");\r
+ }\r
+\r
+ // Delete the BootNext environment variable\r
+ gRT->SetVariable (L"BootNext", &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ 0, NULL);\r
+ }\r
+\r
+ // Clear BootCurrent variable\r
+ gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ 0, NULL);\r
+ }\r
+\r
+ // If Boot Order does not exist then create a default entry\r
+ DefineDefaultBootEntries ();\r
+\r
+ //\r
+ // Update the CRC32 in the EFI System Table header\r
+ //\r
+ gST->Hdr.CRC32 = 0;\r
+ Status = gBS->CalculateCrc32 ((VOID*)gST, gST->Hdr.HeaderSize, &gST->Hdr.CRC32);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ // Timer before initiating the default boot selection\r
+ StartDefaultBootOnTimeout ();\r
+\r
+ // Start the Boot Menu\r
+ Status = BootMenuMain ();\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+}\r
+\r
+EFI_BDS_ARCH_PROTOCOL gBdsProtocol = {\r
+ BdsEntry,\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+BdsInitialize (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &ImageHandle,\r
+ &gEfiBdsArchProtocolGuid, &gBdsProtocol,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r