Implementation for PlatformBootManagerLib library class interfaces.\r
\r
Copyright (C) 2015-2016, Red Hat, Inc.\r
- Copyright (c) 2014 - 2019, ARM Ltd. All rights reserved.<BR>\r
+ Copyright (c) 2014 - 2021, 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
+ Copyright (c) 2021, Semihalf All rights reserved.<BR>\r
\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
#include <Library/UefiBootManagerLib.h>\r
#include <Library/UefiLib.h>\r
#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Protocol/BootManagerPolicy.h>\r
#include <Protocol/DevicePath.h>\r
#include <Protocol/EsrtManagement.h>\r
#include <Protocol/GraphicsOutput.h>\r
#include <Protocol/LoadedImage.h>\r
+#include <Protocol/NonDiscoverableDevice.h>\r
#include <Protocol/PciIo.h>\r
#include <Protocol/PciRootBridgeIo.h>\r
#include <Protocol/PlatformBootManager.h>\r
+#include <Guid/BootDiscoveryPolicy.h>\r
#include <Guid/EventGroup.h>\r
+#include <Guid/NonDiscoverableDevice.h>\r
#include <Guid/TtyTerm.h>\r
#include <Guid/SerialPortLibVendor.h>\r
\r
}\r
\r
\r
+/**\r
+ This FILTER_FUNCTION checks if a handle corresponds to a non-discoverable\r
+ USB host controller.\r
+**/\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+IsUsbHost (\r
+ IN EFI_HANDLE Handle,\r
+ IN CONST CHAR16 *ReportText\r
+ )\r
+{\r
+ NON_DISCOVERABLE_DEVICE *Device;\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->HandleProtocol (Handle,\r
+ &gEdkiiNonDiscoverableDeviceProtocolGuid,\r
+ (VOID **)&Device);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (CompareGuid (Device->Type, &gEdkiiNonDiscoverableUhciDeviceGuid) ||\r
+ CompareGuid (Device->Type, &gEdkiiNonDiscoverableEhciDeviceGuid) ||\r
+ CompareGuid (Device->Type, &gEdkiiNonDiscoverableXhciDeviceGuid)) {\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+\r
/**\r
This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking\r
the matching driver to produce all first-level child handles.\r
PlatformRegisterFvBootOption (\r
CONST EFI_GUID *FileGuid,\r
CHAR16 *Description,\r
- UINT32 Attributes\r
+ UINT32 Attributes,\r
+ EFI_INPUT_KEY *Key\r
)\r
{\r
EFI_STATUS Status;\r
if (OptionIndex == -1) {\r
Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);\r
ASSERT_EFI_ERROR (Status);\r
+ Status = EfiBootManagerAddKeyOptionVariable (NULL,\r
+ (UINT16)NewOption.OptionNumber, 0, Key, NULL);\r
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);\r
}\r
EfiBootManagerFreeLoadOption (&NewOption);\r
EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
//\r
FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);\r
\r
+ //\r
+ // The core BDS code connects short-form USB device paths by explicitly\r
+ // looking for handles with PCI I/O installed, and checking the PCI class\r
+ // code whether it matches the one for a USB host controller. This means\r
+ // non-discoverable USB host controllers need to have the non-discoverable\r
+ // PCI driver attached first.\r
+ //\r
+ FilterAndProcess (&gEdkiiNonDiscoverableDeviceProtocolGuid, IsUsbHost, Connect);\r
+\r
//\r
// Add the hardcoded short-form USB keyboard device path to ConIn.\r
//\r
//\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
\r
#define VERSION_STRING_PREFIX L"Tianocore/EDK2 firmware version "\r
\r
+/**\r
+ This functions checks the value of BootDiscoverPolicy variable and\r
+ connect devices of class specified by that variable. Then it refreshes\r
+ Boot order for newly discovered boot device.\r
+\r
+ @retval EFI_SUCCESS Devices connected successfully or connection\r
+ not required.\r
+ @retval others Return values from GetVariable(), LocateProtocol()\r
+ and ConnectDeviceClass().\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+BootDiscoveryPolicyHandler (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 DiscoveryPolicy;\r
+ UINT32 DiscoveryPolicyOld;\r
+ UINTN Size;\r
+ EFI_BOOT_MANAGER_POLICY_PROTOCOL *BMPolicy;\r
+ EFI_GUID *Class;\r
+\r
+ Size = sizeof (DiscoveryPolicy);\r
+ Status = gRT->GetVariable (\r
+ BOOT_DISCOVERY_POLICY_VAR,\r
+ &gBootDiscoveryPolicyMgrFormsetGuid,\r
+ NULL,\r
+ &Size,\r
+ &DiscoveryPolicy\r
+ );\r
+ if (Status == EFI_NOT_FOUND) {\r
+ DiscoveryPolicy = PcdGet32 (PcdBootDiscoveryPolicy);\r
+ Status = PcdSet32S (PcdBootDiscoveryPolicy, DiscoveryPolicy);\r
+ if (Status == EFI_NOT_FOUND) {\r
+ return EFI_SUCCESS;\r
+ } else if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (DiscoveryPolicy == BDP_CONNECT_MINIMAL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ switch (DiscoveryPolicy) {\r
+ case BDP_CONNECT_NET:\r
+ Class = &gEfiBootManagerPolicyNetworkGuid;\r
+ break;\r
+ case BDP_CONNECT_ALL:\r
+ Class = &gEfiBootManagerPolicyConnectAllGuid;\r
+ break;\r
+ default:\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "%a - Unexpected DiscoveryPolicy (0x%x). Run Minimal Discovery Policy\n",\r
+ __FUNCTION__,\r
+ DiscoveryPolicy\r
+ ));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiBootManagerPolicyProtocolGuid,\r
+ NULL,\r
+ (VOID **)&BMPolicy\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_INFO, "%a - Failed to locate gEfiBootManagerPolicyProtocolGuid."\r
+ "Driver connect will be skipped.\n", __FUNCTION__));\r
+ return Status;\r
+ }\r
+\r
+ Status = BMPolicy->ConnectDeviceClass (BMPolicy, Class);\r
+ if (EFI_ERROR (Status)){\r
+ DEBUG ((DEBUG_ERROR, "%a - ConnectDeviceClass returns - %r\n", __FUNCTION__, Status));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Refresh Boot Options if Boot Discovery Policy has been changed\r
+ //\r
+ Size = sizeof (DiscoveryPolicyOld);\r
+ Status = gRT->GetVariable (\r
+ BOOT_DISCOVERY_POLICY_OLD_VAR,\r
+ &gBootDiscoveryPolicyMgrFormsetGuid,\r
+ NULL,\r
+ &Size,\r
+ &DiscoveryPolicyOld\r
+ );\r
+ if ((Status == EFI_NOT_FOUND) || (DiscoveryPolicyOld != DiscoveryPolicy)) {\r
+ EfiBootManagerRefreshAllBootOption ();\r
+\r
+ Status = gRT->SetVariable (\r
+ BOOT_DISCOVERY_POLICY_OLD_VAR,\r
+ &gBootDiscoveryPolicyMgrFormsetGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ sizeof (DiscoveryPolicyOld),\r
+ &DiscoveryPolicy\r
+ );\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Do the platform specific action after the console is ready\r
Possible things that can be done in PlatformBootManagerAfterConsole:\r
UINTN FirmwareVerLength;\r
UINTN PosX;\r
UINTN PosY;\r
+ EFI_INPUT_KEY Key;\r
\r
FirmwareVerLength = StrLen (PcdGetPtr (PcdFirmwareVersionString));\r
\r
}\r
\r
//\r
- // Connect the rest of the devices.\r
+ // Connect device specified by BootDiscoverPolicy variable and\r
+ // refresh Boot order for newly discovered boot devices\r
//\r
- EfiBootManagerConnectAll ();\r
+ BootDiscoveryPolicyHandler ();\r
\r
//\r
// On ARM, there is currently no reason to use the phased capsule\r
//\r
HandleCapsules ();\r
\r
- //\r
- // Enumerate all possible boot options.\r
- //\r
- EfiBootManagerRefreshAllBootOption ();\r
-\r
//\r
// Register UEFI Shell\r
//\r
- PlatformRegisterFvBootOption (\r
- &gUefiShellFileGuid, L"UEFI Shell", LOAD_OPTION_ACTIVE\r
- );\r
+ Key.ScanCode = SCAN_NULL;\r
+ Key.UnicodeChar = L's';\r
+ PlatformRegisterFvBootOption (&gUefiShellFileGuid, L"UEFI Shell", 0, &Key);\r
}\r
\r
/**\r
VOID\r
)\r
{\r
- return;\r
+ EFI_STATUS Status;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+ UINTN OldBootOptionCount;\r
+ UINTN NewBootOptionCount;\r
+\r
+ //\r
+ // Record the total number of boot configured boot options\r
+ //\r
+ BootOptions = EfiBootManagerGetLoadOptions (&OldBootOptionCount,\r
+ LoadOptionTypeBoot);\r
+ EfiBootManagerFreeLoadOptions (BootOptions, OldBootOptionCount);\r
+\r
+ //\r
+ // Connect all devices, and regenerate all boot options\r
+ //\r
+ EfiBootManagerConnectAll ();\r
+ EfiBootManagerRefreshAllBootOption ();\r
+\r
+ //\r
+ // Record the updated number of boot configured boot options\r
+ //\r
+ BootOptions = EfiBootManagerGetLoadOptions (&NewBootOptionCount,\r
+ LoadOptionTypeBoot);\r
+ EfiBootManagerFreeLoadOptions (BootOptions, NewBootOptionCount);\r
+\r
+ //\r
+ // If the number of configured boot options has changed, reboot\r
+ // the system so the new boot options will be taken into account\r
+ // while executing the ordinary BDS bootflow sequence.\r
+ // *Unless* persistent varstore is being emulated, since we would\r
+ // then end up in an endless reboot loop.\r
+ //\r
+ if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
+ if (NewBootOptionCount != OldBootOptionCount) {\r
+ DEBUG ((DEBUG_WARN, "%a: rebooting after refreshing all boot options\n",\r
+ __FUNCTION__));\r
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
+ }\r
+ }\r
+\r
+ Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ for (;;) {\r
+ EfiBootManagerBoot (&BootManagerMenu);\r
+ }\r
}\r