]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/PlatformBootManagerLib/PlatformBm.c
ArmPkg/PlatformBootManagerLib: reject 'default' parity and stop bit count
[mirror_edk2.git] / ArmPkg / Library / PlatformBootManagerLib / PlatformBm.c
index e95069516216fba3fa24bfa7d16e0f976211f5b7..3411219fbfdb67a1cfe093efe329ff29e43f7ec8 100644 (file)
@@ -2,17 +2,11 @@
   Implementation for PlatformBootManagerLib library class interfaces.\r
 \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) 2014 - 2019, ARM Ltd. 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
-  under the terms and conditions of the BSD License which accompanies this\r
-  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, WITHOUT\r
-  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \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
+#include <Guid/SerialPortLibVendor.h>\r
 \r
 #include "PlatformBm.h"\r
 \r
@@ -46,18 +43,13 @@ typedef struct {
 } PLATFORM_SERIAL_CONSOLE;\r
 #pragma pack ()\r
 \r
-#define SERIAL_DXE_FILE_GUID { \\r
-          0xD3987D4B, 0x971A, 0x435F, \\r
-          { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \\r
-          }\r
-\r
 STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {\r
   //\r
   // VENDOR_DEVICE_PATH SerialDxe\r
   //\r
   {\r
     { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },\r
-    SERIAL_DXE_FILE_GUID\r
+    EDKII_SERIAL_PORT_LIB_VENDOR_GUID\r
   },\r
 \r
   //\r
@@ -390,6 +382,106 @@ PlatformRegisterFvBootOption (
 }\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
@@ -402,6 +494,8 @@ PlatformRegisterOptionsAndKeys (
   EFI_INPUT_KEY                Esc;\r
   EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
 \r
+  GetPlatformOptions ();\r
+\r
   //\r
   // Register ENTER as CONTINUE key\r
   //\r
@@ -450,30 +544,16 @@ PlatformBootManagerBeforeConsole (
   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
   EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
 \r
+  //\r
+  // Dispatch deferred images after EndOfDxe event.\r
+  //\r
+  EfiBootManagerDispatchDeferredImages ();\r
+\r
   //\r
   // Locate the PCI root bridges and make the PCI bus driver connect each,\r
   // non-recursively. This will produce a number of child handles with PciIo on\r
@@ -503,7 +583,13 @@ PlatformBootManagerBeforeConsole (
   //\r
   // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.\r
   //\r
-  ASSERT (FixedPcdGet8 (PcdDefaultTerminalType) == 4);\r
+  STATIC_ASSERT (FixedPcdGet8 (PcdDefaultTerminalType) == 4,\r
+    "PcdDefaultTerminalType must be TTYTERM");\r
+  STATIC_ASSERT (FixedPcdGet8 (PcdUartDefaultParity) != 0,\r
+    "PcdUartDefaultParity must be set to an actual value, not 'default'");\r
+  STATIC_ASSERT (FixedPcdGet8 (PcdUartDefaultStopBits) != 0,\r
+    "PcdUartDefaultStopBits must be set to an actual value, not 'default'");\r
+\r
   CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);\r
 \r
   EfiBootManagerUpdateConsoleVariable (ConIn,\r
@@ -519,15 +605,67 @@ PlatformBootManagerBeforeConsole (
   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
   > Console post action:\r
-    > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
+    > Dynamically switch output mode from 100x31 to 80x25 for certain scenario\r
     > Signal console ready platform customized event\r
   > Run diagnostics like memory testing\r
   > Connect certain devices\r
-  > Dispatch aditional option roms\r
+  > Dispatch additional option roms\r
   > Special boot: e.g.: USB boot, enter UI\r
 **/\r
 VOID\r
@@ -536,32 +674,51 @@ PlatformBootManagerAfterConsole (
   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
@@ -610,3 +767,19 @@ PlatformBootManagerWaitCallback (
     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