\r
Copyright (C) 2015-2016, Red Hat, Inc.\r
Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>\r
- Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>\r
\r
This program and the accompanying materials are licensed and made available\r
#include <Library/PcdLib.h>\r
#include <Library/UefiBootManagerLib.h>\r
#include <Library/UefiLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
#include <Protocol/DevicePath.h>\r
#include <Protocol/EsrtManagement.h>\r
#include <Protocol/GraphicsOutput.h>\r
#include <Protocol/LoadedImage.h>\r
#include <Protocol/PciIo.h>\r
#include <Protocol/PciRootBridgeIo.h>\r
+#include <Protocol/PlatformBootManager.h>\r
#include <Guid/EventGroup.h>\r
#include <Guid/TtyTerm.h>\r
\r
}\r
\r
\r
+STATIC\r
+VOID\r
+GetPlatformOptions (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *CurrentBootOptions;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+ EFI_INPUT_KEY *BootKeys;\r
+ PLATFORM_BOOT_MANAGER_PROTOCOL *PlatformBootManager;\r
+ UINTN CurrentBootOptionCount;\r
+ UINTN Index;\r
+ UINTN BootCount;\r
+\r
+ Status = gBS->LocateProtocol (&gPlatformBootManagerProtocolGuid, NULL,\r
+ (VOID **)&PlatformBootManager);\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+ Status = PlatformBootManager->GetPlatformBootOptionsAndKeys (\r
+ &BootCount,\r
+ &BootOptions,\r
+ &BootKeys\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+ //\r
+ // Fetch the existent boot options. If there are none, CurrentBootCount\r
+ // will be zeroed.\r
+ //\r
+ CurrentBootOptions = EfiBootManagerGetLoadOptions (\r
+ &CurrentBootOptionCount,\r
+ LoadOptionTypeBoot\r
+ );\r
+ //\r
+ // Process the platform boot options.\r
+ //\r
+ for (Index = 0; Index < BootCount; Index++) {\r
+ INTN Match;\r
+ UINTN BootOptionNumber;\r
+\r
+ //\r
+ // If there are any preexistent boot options, and the subject platform boot\r
+ // option is already among them, then don't try to add it. Just get its\r
+ // assigned boot option number so we can associate a hotkey with it. Note\r
+ // that EfiBootManagerFindLoadOption() deals fine with (CurrentBootOptions\r
+ // == NULL) if (CurrentBootCount == 0).\r
+ //\r
+ Match = EfiBootManagerFindLoadOption (\r
+ &BootOptions[Index],\r
+ CurrentBootOptions,\r
+ CurrentBootOptionCount\r
+ );\r
+ if (Match >= 0) {\r
+ BootOptionNumber = CurrentBootOptions[Match].OptionNumber;\r
+ } else {\r
+ //\r
+ // Add the platform boot options as a new one, at the end of the boot\r
+ // order. Note that if the platform provided this boot option with an\r
+ // unassigned option number, then the below function call will assign a\r
+ // number.\r
+ //\r
+ Status = EfiBootManagerAddLoadOptionVariable (\r
+ &BootOptions[Index],\r
+ MAX_UINTN\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a: failed to register \"%s\": %r\n",\r
+ __FUNCTION__, BootOptions[Index].Description, Status));\r
+ continue;\r
+ }\r
+ BootOptionNumber = BootOptions[Index].OptionNumber;\r
+ }\r
+\r
+ //\r
+ // Register a hotkey with the boot option, if requested.\r
+ //\r
+ if (BootKeys[Index].UnicodeChar == L'\0') {\r
+ continue;\r
+ }\r
+\r
+ Status = EfiBootManagerAddKeyOptionVariable (\r
+ NULL,\r
+ BootOptionNumber,\r
+ 0,\r
+ &BootKeys[Index],\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a: failed to register hotkey for \"%s\": %r\n",\r
+ __FUNCTION__, BootOptions[Index].Description, Status));\r
+ }\r
+ }\r
+ EfiBootManagerFreeLoadOptions (CurrentBootOptions, CurrentBootOptionCount);\r
+ EfiBootManagerFreeLoadOptions (BootOptions, BootCount);\r
+ FreePool (BootKeys);\r
+}\r
+\r
STATIC\r
VOID\r
PlatformRegisterOptionsAndKeys (\r
EFI_INPUT_KEY Esc;\r
EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
\r
+ GetPlatformOptions ();\r
+\r
//\r
// Register ENTER as CONTINUE key\r
//\r
VOID\r
)\r
{\r
- EFI_STATUS Status;\r
- ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;\r
-\r
- if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE) {\r
- DEBUG ((DEBUG_INFO, "ProcessCapsules Before EndOfDxe ......\n"));\r
- Status = ProcessCapsules ();\r
- DEBUG ((DEBUG_INFO, "ProcessCapsules returned %r\n", Status));\r
- } else {\r
- if (EsrtManagement != NULL) {\r
- EsrtManagement->SyncEsrtFmp ();\r
- }\r
- }\r
-\r
- Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL,\r
- (VOID **)&EsrtManagement);\r
- if (EFI_ERROR (Status)) {\r
- EsrtManagement = NULL;\r
- }\r
-\r
//\r
// Signal EndOfDxe PI Event\r
//\r
PlatformRegisterOptionsAndKeys ();\r
}\r
\r
+STATIC\r
+VOID\r
+HandleCapsules (\r
+ VOID\r
+ )\r
+{\r
+ ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;\r
+ EFI_PEI_HOB_POINTERS HobPointer;\r
+ EFI_CAPSULE_HEADER *CapsuleHeader;\r
+ BOOLEAN NeedReset;\r
+ EFI_STATUS Status;\r
+\r
+ DEBUG ((DEBUG_INFO, "%a: processing capsules ...\n", __FUNCTION__));\r
+\r
+ Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL,\r
+ (VOID **)&EsrtManagement);\r
+ if (!EFI_ERROR (Status)) {\r
+ EsrtManagement->SyncEsrtFmp ();\r
+ }\r
+\r
+ //\r
+ // Find all capsule images from hob\r
+ //\r
+ HobPointer.Raw = GetHobList ();\r
+ NeedReset = FALSE;\r
+ while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE,\r
+ HobPointer.Raw)) != NULL) {\r
+ CapsuleHeader = (VOID *)(UINTN)HobPointer.Capsule->BaseAddress;\r
+\r
+ Status = ProcessCapsuleImage (CapsuleHeader);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "%a: failed to process capsule %p - %r\n",\r
+ __FUNCTION__, CapsuleHeader, Status));\r
+ return;\r
+ }\r
+\r
+ NeedReset = TRUE;\r
+ HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
+ }\r
+\r
+ if (NeedReset) {\r
+ DEBUG ((DEBUG_WARN, "%a: capsule update successful, resetting ...\n",\r
+ __FUNCTION__));\r
+\r
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
+ CpuDeadLoop();\r
+ }\r
+}\r
+\r
+\r
+#define VERSION_STRING_PREFIX L"Tianocore/EDK2 firmware version "\r
+\r
/**\r
Do the platform specific action after the console is ready\r
Possible things that can be done in PlatformBootManagerAfterConsole:\r
VOID\r
)\r
{\r
- ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;\r
EFI_STATUS Status;\r
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;\r
+ UINTN FirmwareVerLength;\r
+ UINTN PosX;\r
+ UINTN PosY;\r
+\r
+ FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));\r
\r
//\r
// Show the splash screen.\r
//\r
Status = BootLogoEnableLogo ();\r
if (EFI_ERROR (Status)) {\r
+ if (FirmwareVerLength > 0) {\r
+ Print (VERSION_STRING_PREFIX L"%s\n",\r
+ PcdGetPtr (PcdFirmwareVersionString));\r
+ }\r
Print (L"Press ESCAPE for boot options ");\r
+ } else if (FirmwareVerLength > 0) {\r
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle,\r
+ &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);\r
+ if (!EFI_ERROR (Status)) {\r
+ PosX = (GraphicsOutput->Mode->Info->HorizontalResolution -\r
+ (StrLen (VERSION_STRING_PREFIX) + FirmwareVerLength) *\r
+ EFI_GLYPH_WIDTH) / 2;\r
+ PosY = 0;\r
+\r
+ PrintXY (PosX, PosY, NULL, NULL, VERSION_STRING_PREFIX L"%s",\r
+ PcdGetPtr (PcdFirmwareVersionString));\r
+ }\r
}\r
+\r
//\r
// Connect the rest of the devices.\r
//\r
EfiBootManagerConnectAll ();\r
\r
- Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL,\r
- (VOID **)&EsrtManagement);\r
- if (!EFI_ERROR (Status)) {\r
- EsrtManagement->SyncEsrtFmp ();\r
- }\r
-\r
- if (GetBootModeHob() == BOOT_ON_FLASH_UPDATE) {\r
- DEBUG((DEBUG_INFO, "ProcessCapsules After EndOfDxe ......\n"));\r
- Status = ProcessCapsules ();\r
- DEBUG((DEBUG_INFO, "ProcessCapsules returned %r\n", Status));\r
- }\r
+ //\r
+ // On ARM, there is currently no reason to use the phased capsule\r
+ // update approach where some capsules are dispatched before EndOfDxe\r
+ // and some are dispatched after. So just handle all capsules here,\r
+ // when the console is up and we can actually give the user some\r
+ // feedback about what is going on.\r
+ //\r
+ HandleCapsules ();\r
\r
//\r
// Enumerate all possible boot options.\r
Print (L".");\r
}\r
}\r
+\r
+/**\r
+ The function is called when no boot option could be launched,\r
+ including platform recovery options and options pointing to applications\r
+ built into firmware volumes.\r
+\r
+ If this function returns, BDS attempts to enter an infinite loop.\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformBootManagerUnableToBoot (\r
+ VOID\r
+ )\r
+{\r
+ return;\r
+}\r