summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--OvmfPkg/AmdSev/AmdSevX64.dsc21
-rw-r--r--OvmfPkg/AmdSev/AmdSevX64.fdf7
-rw-r--r--OvmfPkg/AmdSev/Grub/.gitignore1
-rw-r--r--OvmfPkg/AmdSev/Grub/Grub.inf39
-rw-r--r--OvmfPkg/AmdSev/Grub/grub.cfg46
-rw-r--r--OvmfPkg/AmdSev/Grub/grub.sh93
-rw-r--r--OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.c1484
-rw-r--r--OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.h175
-rw-r--r--OvmfPkg/Library/PlatformBootManagerLibGrub/PlatformBootManagerLibGrub.inf71
-rw-r--r--OvmfPkg/Library/PlatformBootManagerLibGrub/PlatformData.c214
-rw-r--r--OvmfPkg/OvmfPkg.ci.yaml2
-rw-r--r--OvmfPkg/OvmfPkg.dec1
12 files changed, 2144 insertions, 10 deletions
diff --git a/OvmfPkg/AmdSev/AmdSevX64.dsc b/OvmfPkg/AmdSev/AmdSevX64.dsc
index 59778c4954..18707725b3 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.dsc
+++ b/OvmfPkg/AmdSev/AmdSevX64.dsc
@@ -25,6 +25,7 @@
BUILD_TARGETS = NOOPT|DEBUG|RELEASE
SKUID_IDENTIFIER = DEFAULT
FLASH_DEFINITION = OvmfPkg/AmdSev/AmdSevX64.fdf
+ PREBUILD = sh OvmfPkg/AmdSev/Grub/grub.sh
#
# Defines for default states. These can be changed on the command line.
@@ -35,6 +36,11 @@
DEFINE TPM_CONFIG_ENABLE = FALSE
#
+ # Shell can be useful for debugging but should not be enabled for production
+ #
+ DEFINE BUILD_SHELL = FALSE
+
+ #
# Device drivers
#
DEFINE PVSCSI_ENABLE = TRUE
@@ -149,7 +155,6 @@
UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
DevicePathLib|MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibDevicePathProtocol.inf
- NvVarsFileLib|OvmfPkg/Library/NvVarsFileLib/NvVarsFileLib.inf
FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
@@ -184,9 +189,11 @@
VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
+!if $(BUILD_SHELL) == TRUE
ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf
- S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf
+!endif
+
SmbusLib|MdePkg/Library/BaseSmbusLibNull/BaseSmbusLibNull.inf
OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf
XenHypercallLib|OvmfPkg/Library/XenHypercallLib/XenHypercallLib.inf
@@ -343,7 +350,7 @@
!else
DebugLib|OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
!endif
- PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+ PlatformBootManagerLib|OvmfPkg/Library/PlatformBootManagerLibGrub/PlatformBootManagerLibGrub.inf
PlatformBmPrintScLib|OvmfPkg/Library/PlatformBmPrintScLib/PlatformBmPrintScLib.inf
QemuBootOrderLib|OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -507,6 +514,7 @@
# Point to the MdeModulePkg/Application/UiApp/UiApp.inf
gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 }
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConInConnectOnDemand|TRUE
################################################################################
#
# Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform
@@ -751,8 +759,6 @@
MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
OvmfPkg/AcpiTables/AcpiTables.inf
- MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf
- MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf
MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf
#
@@ -765,12 +771,14 @@
MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
-!if $(TOOL_CHAIN_TAG) != "XCODE5"
+!if $(TOOL_CHAIN_TAG) != "XCODE5" && $(BUILD_SHELL) == TRUE
OvmfPkg/LinuxInitrdDynamicShellCommand/LinuxInitrdDynamicShellCommand.inf {
<PcdsFixedAtBuild>
gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
}
!endif
+ OvmfPkg/AmdSev/Grub/Grub.inf
+!if $(BUILD_SHELL) == TRUE
ShellPkg/Application/Shell/Shell.inf {
<LibraryClasses>
ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
@@ -789,6 +797,7 @@
gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
}
+!endif
OvmfPkg/PlatformDxe/Platform.inf
OvmfPkg/AmdSevDxe/AmdSevDxe.inf
diff --git a/OvmfPkg/AmdSev/AmdSevX64.fdf b/OvmfPkg/AmdSev/AmdSevX64.fdf
index b884166771..1aa9582638 100644
--- a/OvmfPkg/AmdSev/AmdSevX64.fdf
+++ b/OvmfPkg/AmdSev/AmdSevX64.fdf
@@ -257,17 +257,18 @@ INF OvmfPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.inf
INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
INF OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
INF RuleOverride=ACPITABLE OvmfPkg/AcpiTables/AcpiTables.inf
-INF MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf
-INF MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf
INF MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf
INF FatPkg/EnhancedFatDxe/Fat.inf
INF MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
-!if $(TOOL_CHAIN_TAG) != "XCODE5"
+!if $(TOOL_CHAIN_TAG) != "XCODE5" && $(BUILD_SHELL) == TRUE
INF OvmfPkg/LinuxInitrdDynamicShellCommand/LinuxInitrdDynamicShellCommand.inf
!endif
+INF OvmfPkg/AmdSev/Grub/Grub.inf
+!if $(BUILD_SHELL) == TRUE
INF ShellPkg/Application/Shell/Shell.inf
+!endif
INF MdeModulePkg/Logo/LogoDxe.inf
diff --git a/OvmfPkg/AmdSev/Grub/.gitignore b/OvmfPkg/AmdSev/Grub/.gitignore
new file mode 100644
index 0000000000..779a865c4b
--- /dev/null
+++ b/OvmfPkg/AmdSev/Grub/.gitignore
@@ -0,0 +1 @@
+grub.efi
diff --git a/OvmfPkg/AmdSev/Grub/Grub.inf b/OvmfPkg/AmdSev/Grub/Grub.inf
new file mode 100644
index 0000000000..90dc6c7b1e
--- /dev/null
+++ b/OvmfPkg/AmdSev/Grub/Grub.inf
@@ -0,0 +1,39 @@
+## @file
+# Create a Firmware Volume based Grub Bootloader
+#
+# Copyright (C) 2020 James Bottomley, IBM Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = Grub
+ # This is gGrubFileGuid
+ FILE_GUID = b5ae312c-bc8a-43b1-9c62-ebb826dd5d07
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Packages]
+ OvmfPkg/OvmfPkg.dec
+
+#
+# The following information is for reference only and not required by
+# the build tools.
+#
+# VALID_ARCHITECTURES = X64
+#
+
+##
+# Note: The version of grub.efi this picks up can be generated by
+# grub.sh which must be specified as a PREBUILD in the .dsc file. If
+# grub.efi is newer than either grub.sh or grub.cfg then grub.sh will
+# exit with success meaning that if you move your own version of grub
+# in here (after checking out grub.sh and grub.cfg), PREBUILD won't
+# overwrite it.
+##
+[Binaries]
+ PE32|grub.efi|*
+
diff --git a/OvmfPkg/AmdSev/Grub/grub.cfg b/OvmfPkg/AmdSev/Grub/grub.cfg
new file mode 100644
index 0000000000..17be94277a
--- /dev/null
+++ b/OvmfPkg/AmdSev/Grub/grub.cfg
@@ -0,0 +1,46 @@
+## @file
+# Execute a script to recover the SEV supplied secret and use it to
+# decrypt a luks volume. For security, the kernel must be on an encrypted
+# volume so reboot if none are found.
+#
+# Copyright (C) 2020 James Bottomley, IBM Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+echo "Entering grub config"
+sevsecret
+if [ $? -ne 0 ]; then
+ echo "Failed to locate anything in the SEV secret area, prompting for password"
+ cryptomount -a
+else
+ cryptomount -s
+ if [ $? -ne 0 ]; then
+ echo "Failed to mount root securely, retrying with password prompt"
+ cryptomount -a
+ fi
+fi
+set root=
+for f in (crypto*); do
+ if [ -e $f/boot/grub/grub.cfg ]; then
+ set root=$f
+ set prefix=($root)/boot/grub
+ break;
+ fi
+done
+if [ x$root = x ]; then
+ echo "Failed to find any grub configuration on the encrypted volume"
+ sleep 5
+ reboot
+fi
+# rest of modules to get boot to work
+set modules="
+ boot
+ loadenv
+ "
+for f in $modules; do
+ insmod $f
+done
+echo "Transferring to ${prefix}/grub.cfg"
+source $prefix/grub.cfg
diff --git a/OvmfPkg/AmdSev/Grub/grub.sh b/OvmfPkg/AmdSev/Grub/grub.sh
new file mode 100644
index 0000000000..99807d7291
--- /dev/null
+++ b/OvmfPkg/AmdSev/Grub/grub.sh
@@ -0,0 +1,93 @@
+## @file
+# Build a version of grub capable of decrypting a luks volume with a SEV
+# Supplied secret
+#
+# Copyright (C) 2020 James Bottomley, IBM Corporation.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+set -e
+remove_efi=1
+
+cleanup() {
+ # remove the intermediates
+ for f in disk.fat grub-bootstrap.cfg; do
+ rm -f -- "${basedir}/$f"
+ done
+ if [ $remove_efi -eq 1 ]; then
+ rm -f -- "${basedir}/grub.efi"
+ fi
+}
+
+trap cleanup EXIT
+
+GRUB_MODULES="
+ part_msdos
+ part_gpt
+ cryptodisk
+ luks
+ gcry_rijndael
+ gcry_sha256
+ ext2
+ btrfs
+ xfs
+ fat
+ configfile
+ memdisk
+ sleep
+ normal
+ echo
+ test
+ regexp
+ linux
+ linuxefi
+ reboot
+ sevsecret
+ "
+basedir=$(dirname -- "$0")
+
+# don't run a build if grub.efi exists and is newer than the config files
+if [ -e "${basedir}/grub.efi" ] && \
+ [ "${basedir}/grub.efi" -nt "${basedir}/grub.cfg" ] && \
+ [ "${basedir}/grub.efi" -nt "${basedir}/grub.sh" ]; then
+ remove_efi=0
+ echo "preserving existing grub.efi" >&2
+ exit 0
+fi
+
+##
+# different distributions have different names for grub-mkimage, so
+# search all the known ones
+##
+mkimage=
+for b in grub2-mkimage grub-mkimage; do
+ if which "$b" > /dev/null 2>&1; then
+ mkimage="$b"
+ break
+ fi
+done
+if [ -z "$mkimage" ]; then
+ echo "Can't find grub mkimage" >&2
+ exit 1
+fi
+
+# GRUB's rescue parser doesn't understand 'if'.
+echo 'normal (memdisk)/grub.cfg' > "${basedir}/grub-bootstrap.cfg"
+
+# Now build a memdisk with the correct grub.cfg
+rm -f -- "${basedir}/disk.fat"
+mkfs.msdos -C -- "${basedir}/disk.fat" 64
+mcopy -i "${basedir}/disk.fat" -- "${basedir}/grub.cfg" ::grub.cfg
+
+
+${mkimage} -O x86_64-efi \
+ -p '(crypto0)' \
+ -c "${basedir}/grub-bootstrap.cfg" \
+ -m "${basedir}/disk.fat" \
+ -o "${basedir}/grub.efi" \
+ ${GRUB_MODULES}
+
+remove_efi=0
+echo "grub.efi generated in ${basedir}"
diff --git a/OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.c b/OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.c
new file mode 100644
index 0000000000..5c92d4fc2b
--- /dev/null
+++ b/OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.c
@@ -0,0 +1,1484 @@
+/** @file
+ Platform BDS customizations.
+
+ Copyright (C) 2020 James Bottomley, IBM Corporation.
+ Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BdsPlatform.h"
+#include <Guid/RootBridgesConnectedEventGroup.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Library/PlatformBmPrintScLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+
+
+//
+// Global data
+//
+
+VOID *mEfiDevPathNotifyReg;
+EFI_EVENT mEfiDevPathEvent;
+UINT16 mHostBridgeDevId;
+
+//
+// Table of host IRQs matching PCI IRQs A-D
+// (for configuring PCI Interrupt Line register)
+//
+CONST UINT8 PciHostIrqs[] = {
+ 0x0a, 0x0a, 0x0b, 0x0b
+};
+
+//
+// Type definitions
+//
+
+typedef
+EFI_STATUS
+(EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
+ IN EFI_HANDLE Handle,
+ IN VOID *Instance,
+ IN VOID *Context
+ );
+
+/**
+ @param[in] Handle - Handle of PCI device instance
+ @param[in] PciIo - PCI IO protocol instance
+ @param[in] Pci - PCI Header register block
+**/
+typedef
+EFI_STATUS
+(EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
+ IN EFI_HANDLE Handle,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN PCI_TYPE00 *Pci
+ );
+
+
+//
+// Function prototypes
+//
+
+EFI_STATUS
+VisitAllInstancesOfProtocol (
+ IN EFI_GUID *Id,
+ IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+VisitAllPciInstancesOfProtocol (
+ IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
+ );
+
+VOID
+InstallDevicePathCallback (
+ VOID
+ );
+
+VOID
+PlatformRegisterFvBootOption (
+ EFI_GUID *FileGuid,
+ CHAR16 *Description,
+ UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ INTN OptionIndex;
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
+ DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
+ ASSERT (DevicePath != NULL);
+ DevicePath = AppendDevicePathNode (
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
+ );
+ ASSERT (DevicePath != NULL);
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &NewOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ Attributes,
+ Description,
+ DevicePath,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (DevicePath);
+
+ BootOptions = EfiBootManagerGetLoadOptions (
+ &BootOptionCount, LoadOptionTypeBoot
+ );
+
+ OptionIndex = EfiBootManagerFindLoadOption (
+ &NewOption, BootOptions, BootOptionCount
+ );
+
+ if (OptionIndex == -1) {
+ Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
+ ASSERT_EFI_ERROR (Status);
+ }
+ EfiBootManagerFreeLoadOption (&NewOption);
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+/**
+ Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options
+ whose device paths do not resolve exactly to an FvFile in the system.
+
+ Also strip out every boot option that is not an FvFile, meaning the system
+ can only boot either the Grub or (if built) the shell.
+
+ This removes any boot options that point to binaries built into the firmware
+ and have become stale due to any of the following:
+ - DXEFV's base address or size changed (historical),
+ - DXEFV's FvNameGuid changed,
+ - the FILE_GUID of the pointed-to binary changed,
+ - the referenced binary is no longer built into the firmware.
+
+ EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only
+ avoids exact duplicates.
+**/
+VOID
+RemoveStaleFvFileOptions (
+ VOID
+ )
+{
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ UINTN Index;
+
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,
+ LoadOptionTypeBoot);
+
+ for (Index = 0; Index < BootOptionCount; ++Index) {
+ EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
+ EFI_STATUS Status;
+ EFI_HANDLE FvHandle;
+
+ //
+ // If the device path starts with neither MemoryMapped(...) nor Fv(...),
+ // then delete the boot option.
+ //
+ Node1 = BootOptions[Index].FilePath;
+ if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&
+ DevicePathSubType (Node1) == HW_MEMMAP_DP) &&
+ !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {
+ EfiBootManagerDeleteLoadOptionVariable (
+ BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
+ continue;
+ }
+
+ //
+ // If the second device path node is not FvFile(...), then delete the boot
+ // option.
+ //
+ Node2 = NextDevicePathNode (Node1);
+ if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||
+ DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {
+ EfiBootManagerDeleteLoadOptionVariable (
+ BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
+ continue;
+ }
+
+ //
+ // Locate the Firmware Volume2 protocol instance that is denoted by the
+ // boot option. If this lookup fails (i.e., the boot option references a
+ // firmware volume that doesn't exist), then we'll proceed to delete the
+ // boot option.
+ //
+ SearchNode = Node1;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,
+ &SearchNode, &FvHandle);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The firmware volume was found; now let's see if it contains the FvFile
+ // identified by GUID.
+ //
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
+ UINTN BufferSize;
+ EFI_FV_FILETYPE FoundType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINT32 AuthenticationStatus;
+
+ Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **)&FvProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
+ //
+ // Buffer==NULL means we request metadata only: BufferSize, FoundType,
+ // FileAttributes.
+ //
+ Status = FvProtocol->ReadFile (
+ FvProtocol,
+ &FvFileNode->FvFileName, // NameGuid
+ NULL, // Buffer
+ &BufferSize,
+ &FoundType,
+ &FileAttributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The FvFile was found. Keep the boot option.
+ //
+ continue;
+ }
+ }
+
+ //
+ // Delete the boot option.
+ //
+ Status = EfiBootManagerDeleteLoadOptionVariable (
+ BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
+ DEBUG_CODE (
+ CHAR16 *DevicePathString;
+
+ DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,
+ FALSE, FALSE);
+ DEBUG ((
+ EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,
+ "%a: removing stale Boot#%04x %s: %r\n",
+ __FUNCTION__,
+ (UINT32)BootOptions[Index].OptionNumber,
+ DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
+ Status
+ ));
+ if (DevicePathString != NULL) {
+ FreePool (DevicePathString);
+ }
+ );
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+EFI_STATUS
+EFIAPI
+ConnectRootBridge (
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Instance,
+ IN VOID *Context
+ );
+
+STATIC
+EFI_STATUS
+EFIAPI
+ConnectVirtioPciRng (
+ IN EFI_HANDLE Handle,
+ IN VOID *Instance,
+ IN VOID *Context
+ );
+
+//
+// BDS Platform Functions
+//
+/**
+ 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.
+**/
+VOID
+EFIAPI
+PlatformBootManagerBeforeConsole (
+ VOID
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ UINT16 FrontPageTimeout;
+
+ FrontPageTimeout = 0;
+
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerBeforeConsole\n"));
+ InstallDevicePathCallback ();
+
+ VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,
+ ConnectRootBridge, NULL);
+
+ //
+ // Signal the ACPI platform driver that it can download QEMU ACPI tables.
+ //
+ EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
+
+ //
+ // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers
+ // the preparation of S3 system information. That logic has a hard dependency
+ // on the presence of the FACS ACPI table. Since our ACPI tables are only
+ // installed after PCI enumeration completes, we must not trigger the S3 save
+ // earlier, hence we can't signal End-of-Dxe earlier.
+ //
+ EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
+
+ //
+ // Prevent further changes to LockBoxes or SMRAM.
+ //
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (&Handle,
+ &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
+ NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Dispatch deferred images after EndOfDxe event and ReadyToLock
+ // installation.
+ //
+ EfiBootManagerDispatchDeferredImages ();
+
+ PlatformInitializeConsole (gPlatformConsole);
+
+ Status = gRT->SetVariable (
+ EFI_TIME_OUT_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ (EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS),
+ sizeof FrontPageTimeout,
+ &FrontPageTimeout
+ );
+ //
+ // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL
+ // instances on Virtio PCI RNG devices.
+ //
+ VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid, ConnectVirtioPciRng,
+ NULL);
+}
+
+
+EFI_STATUS
+EFIAPI
+ConnectRootBridge (
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Instance,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Make the PCI bus driver connect the root bridge, non-recursively. This
+ // will produce a number of child handles with PciIo on them.
+ //
+ Status = gBS->ConnectController (
+ RootBridgeHandle, // ControllerHandle
+ NULL, // DriverImageHandle
+ NULL, // RemainingDevicePath -- produce all
+ // children
+ FALSE // Recursive
+ );
+ return Status;
+}
+
+
+STATIC
+EFI_STATUS
+EFIAPI
+ConnectVirtioPciRng (
+ IN EFI_HANDLE Handle,
+ IN VOID *Instance,
+ IN VOID *Context
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT8 RevisionId;
+ BOOLEAN Virtio10;
+ UINT16 SubsystemId;
+
+ PciIo = Instance;
+
+ //
+ // Read and check VendorId.
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET,
+ 1, &VendorId);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ if (VendorId != VIRTIO_VENDOR_ID) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Read DeviceId and RevisionId.
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET,
+ 1, &DeviceId);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_REVISION_ID_OFFSET,
+ 1, &RevisionId);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // From DeviceId and RevisionId, determine whether the device is a
+ // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can
+ // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and
+ // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can
+ // only be sanity-checked, and SubsystemId will decide.
+ //
+ if (DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE &&
+ RevisionId >= 0x01) {
+ Virtio10 = TRUE;
+ } else if (DeviceId >= 0x1000 && DeviceId <= 0x103F && RevisionId == 0x00) {
+ Virtio10 = FALSE;
+ } else {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Read and check SubsystemId as dictated by Virtio10.
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16,
+ PCI_SUBSYSTEM_ID_OFFSET, 1, &SubsystemId);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ if ((Virtio10 && SubsystemId >= 0x40) ||
+ (!Virtio10 && SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {
+ Status = gBS->ConnectController (
+ Handle, // ControllerHandle
+ NULL, // DriverImageHandle -- connect all drivers
+ NULL, // RemainingDevicePath -- produce all child handles
+ FALSE // Recursive -- don't follow child handles
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ }
+ return EFI_SUCCESS;
+
+Error:
+ DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));
+ return Status;
+}
+
+
+/**
+ Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.
+
+ @param[in] DeviceHandle Handle of the LPC Bridge device.
+
+ @retval EFI_SUCCESS Console devices on the LPC bridge have been added to
+ ConOut, ConIn, and ErrOut.
+
+ @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
+ from DeviceHandle.
+**/
+EFI_STATUS
+PrepareLpcBridgeDevicePath (
+ IN EFI_HANDLE DeviceHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ CHAR16 *DevPathStr;
+
+ DevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID*)&DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ TempDevicePath = DevicePath;
+
+ //
+ // Register Keyboard
+ //
+ DevicePath = AppendDevicePathNode (DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
+
+ EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
+
+ //
+ // Register COM1
+ //
+ DevicePath = TempDevicePath;
+ gPnp16550ComPortDeviceNode.UID = 0;
+
+ DevicePath = AppendDevicePathNode (DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
+ DevicePath = AppendDevicePathNode (DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
+ DevicePath = AppendDevicePathNode (DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
+
+ //
+ // Print Device Path
+ //
+ DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
+ if (DevPathStr != NULL) {
+ DEBUG((
+ DEBUG_INFO,
+ "BdsPlatform.c+%d: COM%d DevPath: %s\n",
+ __LINE__,
+ gPnp16550ComPortDeviceNode.UID + 1,
+ DevPathStr
+ ));
+ FreePool(DevPathStr);
+ }
+
+ EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+ EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
+ EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+
+ //
+ // Register COM2
+ //
+ DevicePath = TempDevicePath;
+ gPnp16550ComPortDeviceNode.UID = 1;
+
+ DevicePath = AppendDevicePathNode (DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
+ DevicePath = AppendDevicePathNode (DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
+ DevicePath = AppendDevicePathNode (DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
+
+ //
+ // Print Device Path
+ //
+ DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
+ if (DevPathStr != NULL) {
+ DEBUG((
+ DEBUG_INFO,
+ "BdsPlatform.c+%d: COM%d DevPath: %s\n",
+ __LINE__,
+ gPnp16550ComPortDeviceNode.UID + 1,
+ DevPathStr
+ ));
+ FreePool(DevPathStr);
+ }
+
+ EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+ EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
+ EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetGopDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_HANDLE PciDeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
+ UINTN GopHandleCount;
+ EFI_HANDLE *GopHandleBuffer;
+
+ if (PciDevicePath == NULL || GopDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the GopDevicePath to be PciDevicePath
+ //
+ *GopDevicePath = PciDevicePath;
+ TempPciDevicePath = PciDevicePath;
+
+ Status = gBS->LocateDevicePath (
+ &gEfiDevicePathProtocolGuid,
+ &TempPciDevicePath,
+ &PciDeviceHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Try to connect this handle, so that GOP driver could start on this
+ // device and create child handles with GraphicsOutput Protocol installed
+ // on them, then we get device paths of these child handles and select
+ // them as possible console device.
+ //
+ gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiGraphicsOutputProtocolGuid,
+ NULL,
+ &GopHandleCount,
+ &GopHandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Add all the child handles as possible Console Device
+ //
+ for (Index = 0; Index < GopHandleCount; Index++) {
+ Status = gBS->HandleProtocol (GopHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ if (CompareMem (
+ PciDevicePath,
+ TempDevicePath,
+ GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
+ ) == 0) {
+ //
+ // In current implementation, we only enable one of the child handles
+ // as console device, i.e. sotre one of the child handle's device
+ // path to variable "ConOut"
+ // In future, we could select all child handles to be console device
+ //
+
+ *GopDevicePath = TempDevicePath;
+
+ //
+ // Delete the PCI device's path that added by
+ // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.
+ //
+ EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);
+ EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);
+ }
+ }
+ gBS->FreePool (GopHandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add PCI display to ConOut.
+
+ @param[in] DeviceHandle Handle of the PCI display device.
+
+ @retval EFI_SUCCESS The PCI display device has been added to ConOut.
+
+ @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
+ from DeviceHandle.
+**/
+EFI_STATUS
+PreparePciDisplayDevicePath (
+ IN EFI_HANDLE DeviceHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
+
+ DevicePath = NULL;
+ GopDevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID*)&DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GetGopDevicePath (DevicePath, &GopDevicePath);
+ DevicePath = GopDevicePath;
+
+ EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add PCI Serial to ConOut, ConIn, ErrOut.
+
+ @param[in] DeviceHandle Handle of the PCI serial device.
+
+ @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,
+ ErrOut.
+
+ @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing
+ from DeviceHandle.
+**/
+EFI_STATUS
+PreparePciSerialDevicePath (
+ IN EFI_HANDLE DeviceHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ DevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID*)&DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DevicePath = AppendDevicePathNode (DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
+ DevicePath = AppendDevicePathNode (DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
+
+ EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+ EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);
+ EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+VisitAllInstancesOfProtocol (
+ IN EFI_GUID *Id,
+ IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ VOID *Instance;
+
+ //
+ // Start to check all the PciIo to find all possible device
+ //
+ HandleCount = 0;
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ Id,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = (*CallBackFunction) (
+ HandleBuffer[Index],
+ Instance,
+ Context
+ );
+ }
+
+ gBS->FreePool (HandleBuffer);
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+VisitingAPciInstance (
+ IN EFI_HANDLE Handle,
+ IN VOID *Instance,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;
+
+ //
+ // Check for all PCI device
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (
+ Handle,
+ PciIo,
+ &Pci
+ );
+
+}
+
+
+
+EFI_STATUS
+VisitAllPciInstances (
+ IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
+ )
+{
+ return VisitAllInstancesOfProtocol (
+ &gEfiPciIoProtocolGuid,
+ VisitingAPciInstance,
+ (VOID*)(UINTN) CallBackFunction
+ );
+}
+
+
+/**
+ Do platform specific PCI Device check and add them to
+ ConOut, ConIn, ErrOut.
+
+ @param[in] Handle - Handle of PCI device instance
+ @param[in] PciIo - PCI IO protocol instance
+ @param[in] Pci - PCI Header register block
+
+ @retval EFI_SUCCESS - PCI Device check and Console variable update
+ successfully.
+ @retval EFI_STATUS - PCI Device check or Console variable update fail.
+
+**/
+EFI_STATUS
+EFIAPI
+DetectAndPreparePlatformPciDevicePath (
+ IN EFI_HANDLE Handle,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN PCI_TYPE00 *Pci
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Here we decide whether it is LPC Bridge
+ //
+ if ((IS_PCI_LPC (Pci)) ||
+ ((IS_PCI_ISA_PDECODE (Pci)) &&
+ (Pci->Hdr.VendorId == 0x8086) &&
+ (Pci->Hdr.DeviceId == 0x7000)
+ )
+ ) {
+ //
+ // Add IsaKeyboard to ConIn,
+ // add IsaSerial to ConOut, ConIn, ErrOut
+ //
+ DEBUG ((DEBUG_INFO, "Found LPC Bridge device\n"));
+ PrepareLpcBridgeDevicePath (Handle);
+ return EFI_SUCCESS;
+ }
+ //
+ // Here we decide which Serial device to enable in PCI bus
+ //
+ if (IS_PCI_16550SERIAL (Pci)) {
+ //
+ // Add them to ConOut, ConIn, ErrOut.
+ //
+ DEBUG ((DEBUG_INFO, "Found PCI 16550 SERIAL device\n"));
+ PreparePciSerialDevicePath (Handle);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Here we decide which display device to enable in PCI bus
+ //
+ if (IS_PCI_DISPLAY (Pci)) {
+ //
+ // Add them to ConOut.
+ //
+ DEBUG ((DEBUG_INFO, "Found PCI display device\n"));
+ PreparePciDisplayDevicePath (Handle);
+ return EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+
+/**
+ Connect the predefined platform default console device.
+
+ Always try to find and enable PCI display devices.
+
+ @param[in] PlatformConsole Predefined platform default console device array.
+**/
+VOID
+PlatformInitializeConsole (
+ IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole
+ )
+{
+ UINTN Index;
+
+ //
+ // Do platform specific PCI Device check and add them to ConOut, ConIn,
+ // ErrOut
+ //
+ VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
+
+ //
+ // Have chance to connect the platform default console,
+ // the platform default console is the minimum device group
+ // the platform should support
+ //
+ for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
+ //
+ // Update the console variable with the connect type
+ //
+ if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
+ EfiBootManagerUpdateConsoleVariable (ConIn,
+ PlatformConsole[Index].DevicePath, NULL);
+ }
+ if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
+ EfiBootManagerUpdateConsoleVariable (ConOut,
+ PlatformConsole[Index].DevicePath, NULL);
+ }
+ if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
+ EfiBootManagerUpdateConsoleVariable (ErrOut,
+ PlatformConsole[Index].DevicePath, NULL);
+ }
+ }
+}
+
+
+/**
+ Configure PCI Interrupt Line register for applicable devices
+ Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
+
+ @param[in] Handle - Handle of PCI device instance
+ @param[in] PciIo - PCI IO protocol instance
+ @param[in] PciHdr - PCI Header register block
+
+ @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+SetPciIntLine (
+ IN EFI_HANDLE Handle,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN PCI_TYPE00 *PciHdr
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;
+ UINTN RootSlot;
+ UINTN Idx;
+ UINT8 IrqLine;
+ EFI_STATUS Status;
+ UINT32 RootBusNumber;
+
+ Status = EFI_SUCCESS;
+
+ if (PciHdr->Device.InterruptPin != 0) {
+
+ DevPathNode = DevicePathFromHandle (Handle);
+ ASSERT (DevPathNode != NULL);
+ DevPath = DevPathNode;
+
+ RootBusNumber = 0;
+ if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&
+ DevicePathSubType (DevPathNode) == ACPI_DP &&
+ ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {
+ RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;
+ }
+
+ //
+ // Compute index into PciHostIrqs[] table by walking
+ // the device path and adding up all device numbers
+ //
+ Status = EFI_NOT_FOUND;
+ RootSlot = 0;
+ Idx = PciHdr->Device.InterruptPin - 1;
+ while (!IsDevicePathEnd (DevPathNode)) {
+ if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
+ DevicePathSubType (DevPathNode) == HW_PCI_DP) {
+
+ Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
+
+ //
+ // Unlike SeaBIOS, which starts climbing from the leaf device
+ // up toward the root, we traverse the device path starting at
+ // the root moving toward the leaf node.
+ // The slot number of the top-level parent bridge is needed for
+ // Q35 cases with more than 24 slots on the root bus.
+ //
+ if (Status != EFI_SUCCESS) {
+ Status = EFI_SUCCESS;
+ RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
+ }
+ }
+
+ DevPathNode = NextDevicePathNode (DevPathNode);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (RootBusNumber == 0 && RootSlot == 0) {
+ DEBUG((
+ DEBUG_ERROR,
+ "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
+ __FUNCTION__
+ ));
+ ASSERT (FALSE);
+ }
+
+ //
+ // Final PciHostIrqs[] index calculation depends on the platform
+ // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
+ //
+ switch (mHostBridgeDevId) {
+ case INTEL_82441_DEVICE_ID:
+ Idx -= 1;
+ break;
+ case INTEL_Q35_MCH_DEVICE_ID:
+ //
+ // SeaBIOS contains the following comment:
+ // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
+ // with a different starting index - see q35-acpi-dsdt.dsl.
+ //
+ // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
+ //
+ if (RootSlot > 24) {
+ //
+ // in this case, subtract back out RootSlot from Idx
+ // (SeaBIOS never adds it to begin with, but that would make our
+ // device path traversal loop above too awkward)
+ //
+ Idx -= RootSlot;
+ }
+ break;
+ default:
+ ASSERT (FALSE); // should never get here
+ }
+ Idx %= ARRAY_SIZE (PciHostIrqs);
+ IrqLine = PciHostIrqs[Idx];
+
+ DEBUG_CODE_BEGIN ();
+ {
+ CHAR16 *DevPathString;
+ STATIC CHAR16 Fallback[] = L"<failed to convert>";
+ UINTN Segment, Bus, Device, Function;
+
+ DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
+ if (DevPathString == NULL) {
+ DevPathString = Fallback;
+ }
+ Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,
+ (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,
+ IrqLine));
+
+ if (DevPathString != Fallback) {
+ FreePool (DevPathString);
+ }
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
+ //
+ Status = PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_INT_LINE_OFFSET,
+ 1,
+ &IrqLine
+ );
+ }
+
+ return Status;
+}
+
+
+VOID
+PciAcpiInitialization (
+ )
+{
+ UINTN Pmba;
+
+ //
+ // Query Host Bridge DID to determine platform type
+ //
+ mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
+ switch (mHostBridgeDevId) {
+ case INTEL_82441_DEVICE_ID:
+ Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
+ //
+ // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
+ //
+ PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
+ PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
+ PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
+ PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
+ break;
+ case INTEL_Q35_MCH_DEVICE_ID:
+ Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
+ //
+ // 00:1f.0 LPC Bridge (Q35) LNK routing targets
+ //
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
+ break;
+ default:
+ DEBUG ((DEBUG_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
+ __FUNCTION__, mHostBridgeDevId));
+ ASSERT (FALSE);
+ return;
+ }
+
+ //
+ // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
+ //
+ VisitAllPciInstances (SetPciIntLine);
+
+ //
+ // Set ACPI SCI_EN bit in PMCNTRL
+ //
+ IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
+}
+
+EFI_STATUS
+EFIAPI
+ConnectRecursivelyIfPciMassStorage (
+ IN EFI_HANDLE Handle,
+ IN EFI_PCI_IO_PROTOCOL *Instance,
+ IN PCI_TYPE00 *PciHeader
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ CHAR16 *DevPathStr;
+
+ //
+ // Recognize PCI Mass Storage
+ //
+ if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {
+ DevicePath = NULL;
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID*)&DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Print Device Path
+ //
+ DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
+ if (DevPathStr != NULL) {
+ DEBUG((
+ DEBUG_INFO,
+ "Found Mass Storage device: %s\n",
+ DevPathStr
+ ));
+ FreePool(DevPathStr);
+ }
+
+ Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Connect with predefined platform connect sequence.
+
+ The OEM/IBV can customize with their own connect sequence.
+**/
+VOID
+PlatformBdsConnectSequence (
+ VOID
+ )
+{
+ UINTN Index;
+
+ DEBUG ((DEBUG_INFO, "PlatformBdsConnectSequence\n"));
+
+ Index = 0;
+
+ //
+ // Here we can get the customized platform connect sequence
+ // Notes: we can connect with new variable which record the
+ // last time boots connect device path sequence
+ //
+ while (gPlatformConnectSequence[Index] != NULL) {
+ //
+ // Build the platform boot option
+ //
+ EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);
+ Index++;
+ }
+ EfiBootManagerConnectAll ();
+}
+
+/**
+ 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
+**/
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+ VOID
+ )
+{
+ EFI_BOOT_MODE BootMode;
+
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n"));
+
+ //
+ // Get current Boot Mode
+ //
+ BootMode = GetBootModeHob ();
+ DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));
+
+ //
+ // Go the different platform policy with different boot mode
+ // Notes: this part code can be change with the table policy
+ //
+ ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
+
+ //
+ // Logo show
+ //
+ BootLogoEnableLogo ();
+
+ //
+ // Set PCI Interrupt Line registers and ACPI SCI_EN
+ //
+ PciAcpiInitialization ();
+
+ //
+ // Process TPM PPI request
+ //
+ Tcg2PhysicalPresenceLibProcessRequest (NULL);
+
+ //
+ // Perform some platform specific connect sequence
+ //
+ PlatformBdsConnectSequence ();
+
+ EfiBootManagerRefreshAllBootOption ();
+
+ //
+ // Register UEFI Shell (Will be removed if the Shell isn't built
+ // which is the default)
+ //
+ PlatformRegisterFvBootOption (
+ &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+ );
+
+ //
+ // Register Grub
+ //
+ PlatformRegisterFvBootOption (
+ &gGrubFileGuid, L"Grub Bootloader", LOAD_OPTION_ACTIVE
+ );
+
+ RemoveStaleFvFileOptions ();
+
+ PlatformBmPrintScRegisterHandler ();
+}
+
+/**
+ This notification function is invoked when an instance of the
+ EFI_DEVICE_PATH_PROTOCOL is produced.
+
+ @param Event The event that occurred
+ @param Context For EFI compatibility. Not used.
+
+**/
+VOID
+EFIAPI
+NotifyDevPath (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
+ ATAPI_DEVICE_PATH *Atapi;
+
+ //
+ // Examine all new handles
+ //
+ for (;;) {
+ //
+ // Get the next handle
+ //
+ BufferSize = sizeof (Handle);
+ Status = gBS->LocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mEfiDevPathNotifyReg,
+ &BufferSize,
+ &Handle
+ );
+
+ //
+ // If not found, we're done
+ //
+ if (EFI_NOT_FOUND == Status) {
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Get the DevicePath protocol on that handle
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid,
+ (VOID **)&DevPathNode);
+ ASSERT_EFI_ERROR (Status);
+
+ while (!IsDevicePathEnd (DevPathNode)) {
+ //
+ // Find the handler to dump this device path node
+ //
+ if (
+ (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
+ ) {
+ Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
+ PciOr16 (
+ PCI_LIB_ADDRESS (
+ 0,
+ 1,
+ 1,
+ (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
+ ),
+ BIT15
+ );
+ }
+
+ //
+ // Next device path node
+ //
+ DevPathNode = NextDevicePathNode (DevPathNode);
+ }
+ }
+
+ return;
+}
+
+
+VOID
+InstallDevicePathCallback (
+ VOID
+ )
+{
+ DEBUG ((DEBUG_INFO, "Registered NotifyDevPath Event\n"));
+ mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
+ &gEfiDevicePathProtocolGuid,
+ TPL_CALLBACK,
+ NotifyDevPath,
+ NULL,
+ &mEfiDevPathNotifyReg
+ );
+}
+
+/**
+ This function is called each second during the boot manager waits the
+ timeout.
+
+ @param TimeoutRemain The remaining timeout.
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+ UINT16 TimeoutRemain
+ )
+{
+ //
+ // Since the timeout should be forced to zero we should never
+ // Get here
+ //
+ ASSERT (FALSE);
+}
+
+/**
+ The function is called when no boot option could be launched,
+ including platform recovery options and options pointing to applications
+ built into firmware volumes.
+
+ If this function returns, BDS attempts to enter an infinite loop.
+**/
+VOID
+EFIAPI
+PlatformBootManagerUnableToBoot (
+ VOID
+ )
+{
+ //
+ // If we get here something failed about the grub boot but since
+ // We're privy to the secret we must panic and not retry or loop
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+}
diff --git a/OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.h b/OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.h
new file mode 100644
index 0000000000..748c630819
--- /dev/null
+++ b/OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.h
@@ -0,0 +1,175 @@
+/** @file
+ Platform BDS customizations include file.
+
+ Copyright (C) 2020 James Bottomley, IBM Corporation.
+ Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ BdsPlatform.h
+
+Abstract:
+
+ Head file for BDS Platform specific code
+
+**/
+
+#ifndef _PLATFORM_SPECIFIC_BDS_PLATFORM_H_
+#define _PLATFORM_SPECIFIC_BDS_PLATFORM_H_
+
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/SmBios.h>
+#include <IndustryStandard/PeImage.h>
+#include <IndustryStandard/Virtio095.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PciLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/BootLogoLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+
+#include <Protocol/Decompress.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+#include <Protocol/LoadedImage.h>
+
+#include <Guid/Acpi.h>
+#include <Guid/SmBios.h>
+#include <Guid/HobList.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/EventGroup.h>
+#include <Guid/DebugAgentGuid.h>
+
+#include <OvmfPlatforms.h>
+
+extern EFI_DEVICE_PATH_PROTOCOL *gPlatformConnectSequence[];
+extern ACPI_HID_DEVICE_PATH gPnpPs2KeyboardDeviceNode;
+extern ACPI_HID_DEVICE_PATH gPnp16550ComPortDeviceNode;
+extern UART_DEVICE_PATH gUartDeviceNode;
+extern VENDOR_DEVICE_PATH gTerminalTypeDeviceNode;
+
+#define PCI_DEVICE_PATH_NODE(Func, Dev) \
+ { \
+ { \
+ HARDWARE_DEVICE_PATH, \
+ HW_PCI_DP, \
+ { \
+ (UINT8) (sizeof (PCI_DEVICE_PATH)), \
+ (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \
+ } \
+ }, \
+ (Func), \
+ (Dev) \
+ }
+
+#define PNPID_DEVICE_PATH_NODE(PnpId) \
+ { \
+ { \
+ ACPI_DEVICE_PATH, \
+ ACPI_DP, \
+ { \
+ (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \
+ (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \
+ }, \
+ }, \
+ EISA_PNP_ID((PnpId)), \
+ 0 \
+ }
+
+#define gPciIsaBridge \
+ PCI_DEVICE_PATH_NODE(0, 0x1f)
+
+#define gP2PBridge \
+ PCI_DEVICE_PATH_NODE(0, 0x1e)
+
+#define gPnpPs2Keyboard \
+ PNPID_DEVICE_PATH_NODE(0x0303)
+
+#define gPnp16550ComPort \
+ PNPID_DEVICE_PATH_NODE(0x0501)
+
+#define gUart \
+ { \
+ { \
+ MESSAGING_DEVICE_PATH, \
+ MSG_UART_DP, \
+ { \
+ (UINT8) (sizeof (UART_DEVICE_PATH)), \
+ (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8) \
+ } \
+ }, \
+ 0, \
+ 115200, \
+ 8, \
+ 1, \
+ 1 \
+ }
+
+#define gPcAnsiTerminal \
+ { \
+ { \
+ MESSAGING_DEVICE_PATH, \
+ MSG_VENDOR_DP, \
+ { \
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)), \
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) \
+ } \
+ }, \
+ DEVICE_PATH_MESSAGING_PC_ANSI \
+ }
+
+#define gEndEntire \
+ { \
+ END_DEVICE_PATH_TYPE, \
+ END_ENTIRE_DEVICE_PATH_SUBTYPE, \
+ { \
+ END_DEVICE_PATH_LENGTH, \
+ 0 \
+ } \
+ }
+
+#define PCI_CLASS_SCC 0x07
+#define PCI_SUBCLASS_SERIAL 0x00
+#define PCI_IF_16550 0x02
+#define IS_PCI_16550SERIAL(_p) IS_CLASS3 (_p, PCI_CLASS_SCC, PCI_SUBCLASS_SERIAL, PCI_IF_16550)
+#define IS_PCI_ISA_PDECODE(_p) IS_CLASS3 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_ISA_PDECODE, 0)
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN ConnectType;
+} PLATFORM_CONSOLE_CONNECT_ENTRY;
+
+#define CONSOLE_OUT BIT0
+#define CONSOLE_IN BIT1
+#define STD_ERROR BIT2
+extern PLATFORM_CONSOLE_CONNECT_ENTRY gPlatformConsole[];
+extern PLATFORM_CONSOLE_CONNECT_ENTRY gXenPlatformConsole[];
+
+//
+// Platform BDS Functions
+//
+
+VOID
+PlatformInitializeConsole (
+ IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole
+ );
+
+#endif // _PLATFORM_SPECIFIC_BDS_PLATFORM_H_
diff --git a/OvmfPkg/Library/PlatformBootManagerLibGrub/PlatformBootManagerLibGrub.inf b/OvmfPkg/Library/PlatformBootManagerLibGrub/PlatformBootManagerLibGrub.inf
new file mode 100644
index 0000000000..9a806d17ec
--- /dev/null
+++ b/OvmfPkg/Library/PlatformBootManagerLibGrub/PlatformBootManagerLibGrub.inf
@@ -0,0 +1,71 @@
+## @file
+# Platform BDS customizations library.
+#
+# Copyright (C) 2020 James Bottomley, IBM Corporation.
+# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformBootManagerLibGrub
+ FILE_GUID = 3a8f8431-f0c9-4c95-8a1d-04445c582d4e
+ 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 = X64
+#
+
+[Sources]
+ BdsPlatform.c
+ PlatformData.c
+ BdsPlatform.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+ OvmfPkg/OvmfPkg.dec
+ SecurityPkg/SecurityPkg.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+ UefiBootManagerLib
+ BootLogoLib
+ DevicePathLib
+ PciLib
+ UefiLib
+ PlatformBmPrintScLib
+ Tcg2PhysicalPresenceLib
+
+[Pcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits ## CONSUMES
+
+[Protocols]
+ gEfiPciRootBridgeIoProtocolGuid
+ gEfiDxeSmmReadyToLockProtocolGuid # PROTOCOL SOMETIMES_PRODUCED
+ gEfiLoadedImageProtocolGuid # PROTOCOL SOMETIMES_PRODUCED
+ gEfiFirmwareVolume2ProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
+
+[Guids]
+ gEfiEndOfDxeEventGroupGuid
+ gEfiGlobalVariableGuid
+ gRootBridgesConnectedEventGroupGuid
+ gUefiShellFileGuid
+ gGrubFileGuid
diff --git a/OvmfPkg/Library/PlatformBootManagerLibGrub/PlatformData.c b/OvmfPkg/Library/PlatformBootManagerLibGrub/PlatformData.c
new file mode 100644
index 0000000000..e5945727f2
--- /dev/null
+++ b/OvmfPkg/Library/PlatformBootManagerLibGrub/PlatformData.c
@@ -0,0 +1,214 @@
+/** @file
+ Defined the platform specific device path which will be used by
+ platform Bbd to perform the platform policy connect.
+
+ Copyright (C) 2020 James Bottomley, IBM Corporation.
+ Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "BdsPlatform.h"
+#include <Guid/QemuRamfb.h>
+#include <Guid/SerialPortLibVendor.h>
+
+//
+// Vendor UART Device Path structure
+//
+#pragma pack (1)
+typedef struct {
+ VENDOR_DEVICE_PATH VendorHardware;
+ UART_DEVICE_PATH Uart;
+ VENDOR_DEVICE_PATH TerminalType;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} VENDOR_UART_DEVICE_PATH;
+#pragma pack ()
+
+//
+// USB Keyboard Device Path structure
+//
+#pragma pack (1)
+typedef struct {
+ USB_CLASS_DEVICE_PATH Keyboard;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} USB_KEYBOARD_DEVICE_PATH;
+#pragma pack ()
+
+//
+// QemuRamfb Device Path structure
+//
+#pragma pack (1)
+typedef struct {
+ VENDOR_DEVICE_PATH Vendor;
+ ACPI_ADR_DEVICE_PATH AcpiAdr;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} VENDOR_RAMFB_DEVICE_PATH;
+#pragma pack ()
+
+ACPI_HID_DEVICE_PATH gPnpPs2KeyboardDeviceNode = gPnpPs2Keyboard;
+ACPI_HID_DEVICE_PATH gPnp16550ComPortDeviceNode = gPnp16550ComPort;
+UART_DEVICE_PATH gUartDeviceNode = gUart;
+VENDOR_DEVICE_PATH gTerminalTypeDeviceNode = gPcAnsiTerminal;
+
+//
+// Platform specific keyboard device path
+//
+
+
+//
+// Debug Agent UART Device Path
+//
+VENDOR_UART_DEVICE_PATH gDebugAgentUartDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ EFI_DEBUG_AGENT_GUID,
+ },
+ {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_UART_DP,
+ {
+ (UINT8) (sizeof (UART_DEVICE_PATH)),
+ (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0, // Reserved
+ 0, // BaudRate - Default
+ 0, // DataBits - Default
+ 0, // Parity - Default
+ 0, // StopBits - Default
+ },
+ gPcAnsiTerminal,
+ gEndEntire
+};
+
+STATIC USB_KEYBOARD_DEVICE_PATH gUsbKeyboardDevicePath = {
+ {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_USB_CLASS_DP,
+ {
+ (UINT8)sizeof (USB_CLASS_DEVICE_PATH),
+ (UINT8)(sizeof (USB_CLASS_DEVICE_PATH) >> 8)
+ }
+ },
+ 0xFFFF, // VendorId: any
+ 0xFFFF, // ProductId: any
+ 3, // DeviceClass: HID
+ 1, // DeviceSubClass: boot
+ 1 // DeviceProtocol: keyboard
+ },
+ gEndEntire
+};
+
+STATIC VENDOR_RAMFB_DEVICE_PATH gQemuRamfbDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ QEMU_RAMFB_GUID,
+ },
+ {
+ {
+ ACPI_DEVICE_PATH,
+ ACPI_ADR_DP,
+ {
+ (UINT8) (sizeof (ACPI_ADR_DEVICE_PATH)),
+ (UINT8) ((sizeof (ACPI_ADR_DEVICE_PATH)) >> 8)
+ }
+ },
+ ACPI_DISPLAY_ADR (
+ 1, // DeviceIdScheme
+ 0, // HeadId
+ 0, // NonVgaOutput
+ 1, // BiosCanDetect
+ 0, // VendorInfo
+ ACPI_ADR_DISPLAY_TYPE_EXTERNAL_DIGITAL, // Type
+ 0, // Port
+ 0 // Index
+ ),
+ },
+ gEndEntire
+};
+
+STATIC VENDOR_UART_DEVICE_PATH gXenConsoleDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ EDKII_SERIAL_PORT_LIB_VENDOR_GUID
+ },
+ {
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_UART_DP,
+ {
+ (UINT8) (sizeof (UART_DEVICE_PATH)),
+ (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0,
+ FixedPcdGet64 (PcdUartDefaultBaudRate),
+ FixedPcdGet8 (PcdUartDefaultDataBits),
+ FixedPcdGet8 (PcdUartDefaultParity),
+ FixedPcdGet8 (PcdUartDefaultStopBits),
+ },
+ gPcAnsiTerminal,
+ gEndEntire
+};
+
+//
+// Predefined platform default console device path
+//
+PLATFORM_CONSOLE_CONNECT_ENTRY gPlatformConsole[] = {
+ {
+ (EFI_DEVICE_PATH_PROTOCOL *) &gDebugAgentUartDevicePath,
+ (CONSOLE_OUT | CONSOLE_IN | STD_ERROR)
+ },
+ {
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUsbKeyboardDevicePath,
+ CONSOLE_IN
+ },
+ {
+ (EFI_DEVICE_PATH_PROTOCOL *)&gQemuRamfbDevicePath,
+ CONSOLE_OUT
+ },
+ {
+ NULL,
+ 0
+ }
+};
+
+PLATFORM_CONSOLE_CONNECT_ENTRY gXenPlatformConsole[] = {
+ {
+ (EFI_DEVICE_PATH_PROTOCOL *)&gXenConsoleDevicePath,
+ (CONSOLE_OUT | CONSOLE_IN | STD_ERROR)
+ },
+ {
+ NULL,
+ 0
+ }
+};
+
+//
+// Predefined platform connect sequence
+//
+EFI_DEVICE_PATH_PROTOCOL *gPlatformConnectSequence[] = { NULL };
+
diff --git a/OvmfPkg/OvmfPkg.ci.yaml b/OvmfPkg/OvmfPkg.ci.yaml
index 0d6a78ff5b..9326e6baa6 100644
--- a/OvmfPkg/OvmfPkg.ci.yaml
+++ b/OvmfPkg/OvmfPkg.ci.yaml
@@ -79,7 +79,7 @@
"IgnoreGuidName": ["ResetVector", "XenResetVector"], # Expected duplication for gEfiFirmwareVolumeTopFileGuid
"IgnoreGuidValue": [],
"IgnoreFoldersAndFiles": [],
- "IgnoreDuplicates": [],
+ "IgnoreDuplicates": ["gGrubFileGuid=Grub"],
},
## options defined .pytool/Plugin/LibraryClassCheck
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 6abde4fd93..3fbf7a0ee1 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -116,6 +116,7 @@
gEfiLegacyDevOrderVariableGuid = {0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52}}
gLinuxEfiInitrdMediaGuid = {0x5568e427, 0x68fc, 0x4f3d, {0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68}}
gQemuKernelLoaderFsMediaGuid = {0x1428f772, 0xb64a, 0x441e, {0xb8, 0xc3, 0x9e, 0xbd, 0xd7, 0xf8, 0x93, 0xc7}}
+ gGrubFileGuid = {0xb5ae312c, 0xbc8a, 0x43b1, {0x9c, 0x62, 0xeb, 0xb8, 0x26, 0xdd, 0x5d, 0x07}}
[Ppis]
# PPI whose presence in the PPI database signals that the TPM base address