--- /dev/null
+/** @file\r
+ Platform BDS customizations.\r
+\r
+ Copyright (C) 2020 James Bottomley, IBM Corporation.\r
+ Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "BdsPlatform.h"\r
+#include <Guid/RootBridgesConnectedEventGroup.h>\r
+#include <Protocol/FirmwareVolume2.h>\r
+#include <Library/PlatformBmPrintScLib.h>\r
+#include <Library/Tcg2PhysicalPresenceLib.h>\r
+\r
+\r
+//\r
+// Global data\r
+//\r
+\r
+VOID *mEfiDevPathNotifyReg;\r
+EFI_EVENT mEfiDevPathEvent;\r
+UINT16 mHostBridgeDevId;\r
+\r
+//\r
+// Table of host IRQs matching PCI IRQs A-D\r
+// (for configuring PCI Interrupt Line register)\r
+//\r
+CONST UINT8 PciHostIrqs[] = {\r
+ 0x0a, 0x0a, 0x0b, 0x0b\r
+};\r
+\r
+//\r
+// Type definitions\r
+//\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(\r
+ IN EFI_HANDLE Handle,\r
+ IN VOID *Instance,\r
+ IN VOID *Context\r
+ );\r
+\r
+/**\r
+ @param[in] Handle - Handle of PCI device instance\r
+ @param[in] PciIo - PCI IO protocol instance\r
+ @param[in] Pci - PCI Header register block\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN PCI_TYPE00 *Pci\r
+ );\r
+\r
+\r
+//\r
+// Function prototypes\r
+//\r
+\r
+EFI_STATUS\r
+VisitAllInstancesOfProtocol (\r
+ IN EFI_GUID *Id,\r
+ IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,\r
+ IN VOID *Context\r
+ );\r
+\r
+EFI_STATUS\r
+VisitAllPciInstancesOfProtocol (\r
+ IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction\r
+ );\r
+\r
+VOID\r
+InstallDevicePathCallback (\r
+ VOID\r
+ );\r
+\r
+VOID\r
+PlatformRegisterFvBootOption (\r
+ EFI_GUID *FileGuid,\r
+ CHAR16 *Description,\r
+ UINT32 Attributes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ INTN OptionIndex;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+ UINTN BootOptionCount;\r
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;\r
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+\r
+ Status = gBS->HandleProtocol (\r
+ gImageHandle,\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID **) &LoadedImage\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);\r
+ DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);\r
+ ASSERT (DevicePath != NULL);\r
+ DevicePath = AppendDevicePathNode (\r
+ DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
+ );\r
+ ASSERT (DevicePath != NULL);\r
+\r
+ Status = EfiBootManagerInitializeLoadOption (\r
+ &NewOption,\r
+ LoadOptionNumberUnassigned,\r
+ LoadOptionTypeBoot,\r
+ Attributes,\r
+ Description,\r
+ DevicePath,\r
+ NULL,\r
+ 0\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ FreePool (DevicePath);\r
+\r
+ BootOptions = EfiBootManagerGetLoadOptions (\r
+ &BootOptionCount, LoadOptionTypeBoot\r
+ );\r
+\r
+ OptionIndex = EfiBootManagerFindLoadOption (\r
+ &NewOption, BootOptions, BootOptionCount\r
+ );\r
+\r
+ if (OptionIndex == -1) {\r
+ Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ EfiBootManagerFreeLoadOption (&NewOption);\r
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+}\r
+\r
+/**\r
+ Remove all MemoryMapped(...)/FvFile(...) and Fv(...)/FvFile(...) boot options\r
+ whose device paths do not resolve exactly to an FvFile in the system.\r
+\r
+ Also strip out every boot option that is not an FvFile, meaning the system\r
+ can only boot either the Grub or (if built) the shell.\r
+\r
+ This removes any boot options that point to binaries built into the firmware\r
+ and have become stale due to any of the following:\r
+ - DXEFV's base address or size changed (historical),\r
+ - DXEFV's FvNameGuid changed,\r
+ - the FILE_GUID of the pointed-to binary changed,\r
+ - the referenced binary is no longer built into the firmware.\r
+\r
+ EfiBootManagerFindLoadOption() used in PlatformRegisterFvBootOption() only\r
+ avoids exact duplicates.\r
+**/\r
+VOID\r
+RemoveStaleFvFileOptions (\r
+ VOID\r
+ )\r
+{\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+ UINTN BootOptionCount;\r
+ UINTN Index;\r
+\r
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,\r
+ LoadOptionTypeBoot);\r
+\r
+ for (Index = 0; Index < BootOptionCount; ++Index) {\r
+ EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE FvHandle;\r
+\r
+ //\r
+ // If the device path starts with neither MemoryMapped(...) nor Fv(...),\r
+ // then delete the boot option.\r
+ //\r
+ Node1 = BootOptions[Index].FilePath;\r
+ if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH &&\r
+ DevicePathSubType (Node1) == HW_MEMMAP_DP) &&\r
+ !(DevicePathType (Node1) == MEDIA_DEVICE_PATH &&\r
+ DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP)) {\r
+ EfiBootManagerDeleteLoadOptionVariable (\r
+ BootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // If the second device path node is not FvFile(...), then delete the boot\r
+ // option.\r
+ //\r
+ Node2 = NextDevicePathNode (Node1);\r
+ if (DevicePathType (Node2) != MEDIA_DEVICE_PATH ||\r
+ DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP) {\r
+ EfiBootManagerDeleteLoadOptionVariable (\r
+ BootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Locate the Firmware Volume2 protocol instance that is denoted by the\r
+ // boot option. If this lookup fails (i.e., the boot option references a\r
+ // firmware volume that doesn't exist), then we'll proceed to delete the\r
+ // boot option.\r
+ //\r
+ SearchNode = Node1;\r
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,\r
+ &SearchNode, &FvHandle);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // The firmware volume was found; now let's see if it contains the FvFile\r
+ // identified by GUID.\r
+ //\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;\r
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;\r
+ UINTN BufferSize;\r
+ EFI_FV_FILETYPE FoundType;\r
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;\r
+ UINT32 AuthenticationStatus;\r
+\r
+ Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,\r
+ (VOID **)&FvProtocol);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;\r
+ //\r
+ // Buffer==NULL means we request metadata only: BufferSize, FoundType,\r
+ // FileAttributes.\r
+ //\r
+ Status = FvProtocol->ReadFile (\r
+ FvProtocol,\r
+ &FvFileNode->FvFileName, // NameGuid\r
+ NULL, // Buffer\r
+ &BufferSize,\r
+ &FoundType,\r
+ &FileAttributes,\r
+ &AuthenticationStatus\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // The FvFile was found. Keep the boot option.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Delete the boot option.\r
+ //\r
+ Status = EfiBootManagerDeleteLoadOptionVariable (\r
+ BootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
+ DEBUG_CODE (\r
+ CHAR16 *DevicePathString;\r
+\r
+ DevicePathString = ConvertDevicePathToText(BootOptions[Index].FilePath,\r
+ FALSE, FALSE);\r
+ DEBUG ((\r
+ EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,\r
+ "%a: removing stale Boot#%04x %s: %r\n",\r
+ __FUNCTION__,\r
+ (UINT32)BootOptions[Index].OptionNumber,\r
+ DevicePathString == NULL ? L"<unavailable>" : DevicePathString,\r
+ Status\r
+ ));\r
+ if (DevicePathString != NULL) {\r
+ FreePool (DevicePathString);\r
+ }\r
+ );\r
+ }\r
+\r
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+ConnectRootBridge (\r
+ IN EFI_HANDLE RootBridgeHandle,\r
+ IN VOID *Instance,\r
+ IN VOID *Context\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+ConnectVirtioPciRng (\r
+ IN EFI_HANDLE Handle,\r
+ IN VOID *Instance,\r
+ IN VOID *Context\r
+ );\r
+\r
+//\r
+// BDS Platform Functions\r
+//\r
+/**\r
+ Do the platform init, can be customized by OEM/IBV\r
+\r
+ Possible things that can be done in PlatformBootManagerBeforeConsole:\r
+\r
+ > Update console variable: 1. include hot-plug devices;\r
+ > 2. Clear ConIn and add SOL for AMT\r
+ > Register new Driver#### or Boot####\r
+ > Register new Key####: e.g.: F12\r
+ > Signal ReadyToLock event\r
+ > Authentication action: 1. connect Auth devices;\r
+ > 2. Identify auto logon user.\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformBootManagerBeforeConsole (\r
+ VOID\r
+ )\r
+{\r
+ EFI_HANDLE Handle;\r
+ EFI_STATUS Status;\r
+ UINT16 FrontPageTimeout;\r
+\r
+ FrontPageTimeout = 0;\r
+\r
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerBeforeConsole\n"));\r
+ InstallDevicePathCallback ();\r
+\r
+ VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,\r
+ ConnectRootBridge, NULL);\r
+\r
+ //\r
+ // Signal the ACPI platform driver that it can download QEMU ACPI tables.\r
+ //\r
+ EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);\r
+\r
+ //\r
+ // We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers\r
+ // the preparation of S3 system information. That logic has a hard dependency\r
+ // on the presence of the FACS ACPI table. Since our ACPI tables are only\r
+ // installed after PCI enumeration completes, we must not trigger the S3 save\r
+ // earlier, hence we can't signal End-of-Dxe earlier.\r
+ //\r
+ EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);\r
+\r
+ //\r
+ // Prevent further changes to LockBoxes or SMRAM.\r
+ //\r
+ Handle = NULL;\r
+ Status = gBS->InstallProtocolInterface (&Handle,\r
+ &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,\r
+ NULL);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Dispatch deferred images after EndOfDxe event and ReadyToLock\r
+ // installation.\r
+ //\r
+ EfiBootManagerDispatchDeferredImages ();\r
+\r
+ PlatformInitializeConsole (gPlatformConsole);\r
+\r
+ Status = gRT->SetVariable (\r
+ EFI_TIME_OUT_VARIABLE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ (EFI_VARIABLE_NON_VOLATILE |\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
+ EFI_VARIABLE_RUNTIME_ACCESS),\r
+ sizeof FrontPageTimeout,\r
+ &FrontPageTimeout\r
+ );\r
+ //\r
+ // Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL\r
+ // instances on Virtio PCI RNG devices.\r
+ //\r
+ VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid, ConnectVirtioPciRng,\r
+ NULL);\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+ConnectRootBridge (\r
+ IN EFI_HANDLE RootBridgeHandle,\r
+ IN VOID *Instance,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Make the PCI bus driver connect the root bridge, non-recursively. This\r
+ // will produce a number of child handles with PciIo on them.\r
+ //\r
+ Status = gBS->ConnectController (\r
+ RootBridgeHandle, // ControllerHandle\r
+ NULL, // DriverImageHandle\r
+ NULL, // RemainingDevicePath -- produce all\r
+ // children\r
+ FALSE // Recursive\r
+ );\r
+ return Status;\r
+}\r
+\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+ConnectVirtioPciRng (\r
+ IN EFI_HANDLE Handle,\r
+ IN VOID *Instance,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+ UINT16 VendorId;\r
+ UINT16 DeviceId;\r
+ UINT8 RevisionId;\r
+ BOOLEAN Virtio10;\r
+ UINT16 SubsystemId;\r
+\r
+ PciIo = Instance;\r
+\r
+ //\r
+ // Read and check VendorId.\r
+ //\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET,\r
+ 1, &VendorId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ if (VendorId != VIRTIO_VENDOR_ID) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Read DeviceId and RevisionId.\r
+ //\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET,\r
+ 1, &DeviceId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_REVISION_ID_OFFSET,\r
+ 1, &RevisionId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+\r
+ //\r
+ // From DeviceId and RevisionId, determine whether the device is a\r
+ // modern-only Virtio 1.0 device. In case of Virtio 1.0, DeviceId can\r
+ // immediately be restricted to VIRTIO_SUBSYSTEM_ENTROPY_SOURCE, and\r
+ // SubsystemId will only play a sanity-check role. Otherwise, DeviceId can\r
+ // only be sanity-checked, and SubsystemId will decide.\r
+ //\r
+ if (DeviceId == 0x1040 + VIRTIO_SUBSYSTEM_ENTROPY_SOURCE &&\r
+ RevisionId >= 0x01) {\r
+ Virtio10 = TRUE;\r
+ } else if (DeviceId >= 0x1000 && DeviceId <= 0x103F && RevisionId == 0x00) {\r
+ Virtio10 = FALSE;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Read and check SubsystemId as dictated by Virtio10.\r
+ //\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16,\r
+ PCI_SUBSYSTEM_ID_OFFSET, 1, &SubsystemId);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ if ((Virtio10 && SubsystemId >= 0x40) ||\r
+ (!Virtio10 && SubsystemId == VIRTIO_SUBSYSTEM_ENTROPY_SOURCE)) {\r
+ Status = gBS->ConnectController (\r
+ Handle, // ControllerHandle\r
+ NULL, // DriverImageHandle -- connect all drivers\r
+ NULL, // RemainingDevicePath -- produce all child handles\r
+ FALSE // Recursive -- don't follow child handles\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ }\r
+ return EFI_SUCCESS;\r
+\r
+Error:\r
+ DEBUG ((DEBUG_ERROR, "%a: %r\n", __FUNCTION__, Status));\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Add IsaKeyboard to ConIn; add IsaSerial to ConOut, ConIn, ErrOut.\r
+\r
+ @param[in] DeviceHandle Handle of the LPC Bridge device.\r
+\r
+ @retval EFI_SUCCESS Console devices on the LPC bridge have been added to\r
+ ConOut, ConIn, and ErrOut.\r
+\r
+ @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
+ from DeviceHandle.\r
+**/\r
+EFI_STATUS\r
+PrepareLpcBridgeDevicePath (\r
+ IN EFI_HANDLE DeviceHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
+ CHAR16 *DevPathStr;\r
+\r
+ DevicePath = NULL;\r
+ Status = gBS->HandleProtocol (\r
+ DeviceHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID*)&DevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ TempDevicePath = DevicePath;\r
+\r
+ //\r
+ // Register Keyboard\r
+ //\r
+ DevicePath = AppendDevicePathNode (DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);\r
+\r
+ EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
+\r
+ //\r
+ // Register COM1\r
+ //\r
+ DevicePath = TempDevicePath;\r
+ gPnp16550ComPortDeviceNode.UID = 0;\r
+\r
+ DevicePath = AppendDevicePathNode (DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);\r
+ DevicePath = AppendDevicePathNode (DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
+ DevicePath = AppendDevicePathNode (DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
+\r
+ //\r
+ // Print Device Path\r
+ //\r
+ DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
+ if (DevPathStr != NULL) {\r
+ DEBUG((\r
+ DEBUG_INFO,\r
+ "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
+ __LINE__,\r
+ gPnp16550ComPortDeviceNode.UID + 1,\r
+ DevPathStr\r
+ ));\r
+ FreePool(DevPathStr);\r
+ }\r
+\r
+ EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
+ EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
+ EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
+\r
+ //\r
+ // Register COM2\r
+ //\r
+ DevicePath = TempDevicePath;\r
+ gPnp16550ComPortDeviceNode.UID = 1;\r
+\r
+ DevicePath = AppendDevicePathNode (DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);\r
+ DevicePath = AppendDevicePathNode (DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
+ DevicePath = AppendDevicePathNode (DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
+\r
+ //\r
+ // Print Device Path\r
+ //\r
+ DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
+ if (DevPathStr != NULL) {\r
+ DEBUG((\r
+ DEBUG_INFO,\r
+ "BdsPlatform.c+%d: COM%d DevPath: %s\n",\r
+ __LINE__,\r
+ gPnp16550ComPortDeviceNode.UID + 1,\r
+ DevPathStr\r
+ ));\r
+ FreePool(DevPathStr);\r
+ }\r
+\r
+ EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
+ EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
+ EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+GetGopDevicePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,\r
+ OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE PciDeviceHandle;\r
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;\r
+ UINTN GopHandleCount;\r
+ EFI_HANDLE *GopHandleBuffer;\r
+\r
+ if (PciDevicePath == NULL || GopDevicePath == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Initialize the GopDevicePath to be PciDevicePath\r
+ //\r
+ *GopDevicePath = PciDevicePath;\r
+ TempPciDevicePath = PciDevicePath;\r
+\r
+ Status = gBS->LocateDevicePath (\r
+ &gEfiDevicePathProtocolGuid,\r
+ &TempPciDevicePath,\r
+ &PciDeviceHandle\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Try to connect this handle, so that GOP driver could start on this\r
+ // device and create child handles with GraphicsOutput Protocol installed\r
+ // on them, then we get device paths of these child handles and select\r
+ // them as possible console device.\r
+ //\r
+ gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);\r
+\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiGraphicsOutputProtocolGuid,\r
+ NULL,\r
+ &GopHandleCount,\r
+ &GopHandleBuffer\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Add all the child handles as possible Console Device\r
+ //\r
+ for (Index = 0; Index < GopHandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (GopHandleBuffer[Index],\r
+ &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ if (CompareMem (\r
+ PciDevicePath,\r
+ TempDevicePath,\r
+ GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH\r
+ ) == 0) {\r
+ //\r
+ // In current implementation, we only enable one of the child handles\r
+ // as console device, i.e. sotre one of the child handle's device\r
+ // path to variable "ConOut"\r
+ // In future, we could select all child handles to be console device\r
+ //\r
+\r
+ *GopDevicePath = TempDevicePath;\r
+\r
+ //\r
+ // Delete the PCI device's path that added by\r
+ // GetPlugInPciVgaDevicePath(). Add the integrity GOP device path.\r
+ //\r
+ EfiBootManagerUpdateConsoleVariable (ConOutDev, NULL, PciDevicePath);\r
+ EfiBootManagerUpdateConsoleVariable (ConOutDev, TempDevicePath, NULL);\r
+ }\r
+ }\r
+ gBS->FreePool (GopHandleBuffer);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Add PCI display to ConOut.\r
+\r
+ @param[in] DeviceHandle Handle of the PCI display device.\r
+\r
+ @retval EFI_SUCCESS The PCI display device has been added to ConOut.\r
+\r
+ @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
+ from DeviceHandle.\r
+**/\r
+EFI_STATUS\r
+PreparePciDisplayDevicePath (\r
+ IN EFI_HANDLE DeviceHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;\r
+\r
+ DevicePath = NULL;\r
+ GopDevicePath = NULL;\r
+ Status = gBS->HandleProtocol (\r
+ DeviceHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID*)&DevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ GetGopDevicePath (DevicePath, &GopDevicePath);\r
+ DevicePath = GopDevicePath;\r
+\r
+ EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Add PCI Serial to ConOut, ConIn, ErrOut.\r
+\r
+ @param[in] DeviceHandle Handle of the PCI serial device.\r
+\r
+ @retval EFI_SUCCESS The PCI serial device has been added to ConOut, ConIn,\r
+ ErrOut.\r
+\r
+ @return Error codes, due to EFI_DEVICE_PATH_PROTOCOL missing\r
+ from DeviceHandle.\r
+**/\r
+EFI_STATUS\r
+PreparePciSerialDevicePath (\r
+ IN EFI_HANDLE DeviceHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+\r
+ DevicePath = NULL;\r
+ Status = gBS->HandleProtocol (\r
+ DeviceHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID*)&DevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DevicePath = AppendDevicePathNode (DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);\r
+ DevicePath = AppendDevicePathNode (DevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);\r
+\r
+ EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);\r
+ EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL);\r
+ EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+VisitAllInstancesOfProtocol (\r
+ IN EFI_GUID *Id,\r
+ IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN HandleCount;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN Index;\r
+ VOID *Instance;\r
+\r
+ //\r
+ // Start to check all the PciIo to find all possible device\r
+ //\r
+ HandleCount = 0;\r
+ HandleBuffer = NULL;\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ Id,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ Status = (*CallBackFunction) (\r
+ HandleBuffer[Index],\r
+ Instance,\r
+ Context\r
+ );\r
+ }\r
+\r
+ gBS->FreePool (HandleBuffer);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+VisitingAPciInstance (\r
+ IN EFI_HANDLE Handle,\r
+ IN VOID *Instance,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ PCI_TYPE00 Pci;\r
+\r
+ PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;\r
+\r
+ //\r
+ // Check for all PCI device\r
+ //\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ sizeof (Pci) / sizeof (UINT32),\r
+ &Pci\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (\r
+ Handle,\r
+ PciIo,\r
+ &Pci\r
+ );\r
+\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+VisitAllPciInstances (\r
+ IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction\r
+ )\r
+{\r
+ return VisitAllInstancesOfProtocol (\r
+ &gEfiPciIoProtocolGuid,\r
+ VisitingAPciInstance,\r
+ (VOID*)(UINTN) CallBackFunction\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Do platform specific PCI Device check and add them to\r
+ ConOut, ConIn, ErrOut.\r
+\r
+ @param[in] Handle - Handle of PCI device instance\r
+ @param[in] PciIo - PCI IO protocol instance\r
+ @param[in] Pci - PCI Header register block\r
+\r
+ @retval EFI_SUCCESS - PCI Device check and Console variable update\r
+ successfully.\r
+ @retval EFI_STATUS - PCI Device check or Console variable update fail.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DetectAndPreparePlatformPciDevicePath (\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN PCI_TYPE00 *Pci\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ EFI_PCI_DEVICE_ENABLE,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Here we decide whether it is LPC Bridge\r
+ //\r
+ if ((IS_PCI_LPC (Pci)) ||\r
+ ((IS_PCI_ISA_PDECODE (Pci)) &&\r
+ (Pci->Hdr.VendorId == 0x8086) &&\r
+ (Pci->Hdr.DeviceId == 0x7000)\r
+ )\r
+ ) {\r
+ //\r
+ // Add IsaKeyboard to ConIn,\r
+ // add IsaSerial to ConOut, ConIn, ErrOut\r
+ //\r
+ DEBUG ((DEBUG_INFO, "Found LPC Bridge device\n"));\r
+ PrepareLpcBridgeDevicePath (Handle);\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // Here we decide which Serial device to enable in PCI bus\r
+ //\r
+ if (IS_PCI_16550SERIAL (Pci)) {\r
+ //\r
+ // Add them to ConOut, ConIn, ErrOut.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "Found PCI 16550 SERIAL device\n"));\r
+ PreparePciSerialDevicePath (Handle);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Here we decide which display device to enable in PCI bus\r
+ //\r
+ if (IS_PCI_DISPLAY (Pci)) {\r
+ //\r
+ // Add them to ConOut.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "Found PCI display device\n"));\r
+ PreparePciDisplayDevicePath (Handle);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Connect the predefined platform default console device.\r
+\r
+ Always try to find and enable PCI display devices.\r
+\r
+ @param[in] PlatformConsole Predefined platform default console device array.\r
+**/\r
+VOID\r
+PlatformInitializeConsole (\r
+ IN PLATFORM_CONSOLE_CONNECT_ENTRY *PlatformConsole\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ //\r
+ // Do platform specific PCI Device check and add them to ConOut, ConIn,\r
+ // ErrOut\r
+ //\r
+ VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);\r
+\r
+ //\r
+ // Have chance to connect the platform default console,\r
+ // the platform default console is the minimum device group\r
+ // the platform should support\r
+ //\r
+ for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {\r
+ //\r
+ // Update the console variable with the connect type\r
+ //\r
+ if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {\r
+ EfiBootManagerUpdateConsoleVariable (ConIn,\r
+ PlatformConsole[Index].DevicePath, NULL);\r
+ }\r
+ if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {\r
+ EfiBootManagerUpdateConsoleVariable (ConOut,\r
+ PlatformConsole[Index].DevicePath, NULL);\r
+ }\r
+ if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {\r
+ EfiBootManagerUpdateConsoleVariable (ErrOut,\r
+ PlatformConsole[Index].DevicePath, NULL);\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Configure PCI Interrupt Line register for applicable devices\r
+ Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()\r
+\r
+ @param[in] Handle - Handle of PCI device instance\r
+ @param[in] PciIo - PCI IO protocol instance\r
+ @param[in] PciHdr - PCI Header register block\r
+\r
+ @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetPciIntLine (\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN PCI_TYPE00 *PciHdr\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
+ UINTN RootSlot;\r
+ UINTN Idx;\r
+ UINT8 IrqLine;\r
+ EFI_STATUS Status;\r
+ UINT32 RootBusNumber;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (PciHdr->Device.InterruptPin != 0) {\r
+\r
+ DevPathNode = DevicePathFromHandle (Handle);\r
+ ASSERT (DevPathNode != NULL);\r
+ DevPath = DevPathNode;\r
+\r
+ RootBusNumber = 0;\r
+ if (DevicePathType (DevPathNode) == ACPI_DEVICE_PATH &&\r
+ DevicePathSubType (DevPathNode) == ACPI_DP &&\r
+ ((ACPI_HID_DEVICE_PATH *)DevPathNode)->HID == EISA_PNP_ID(0x0A03)) {\r
+ RootBusNumber = ((ACPI_HID_DEVICE_PATH *)DevPathNode)->UID;\r
+ }\r
+\r
+ //\r
+ // Compute index into PciHostIrqs[] table by walking\r
+ // the device path and adding up all device numbers\r
+ //\r
+ Status = EFI_NOT_FOUND;\r
+ RootSlot = 0;\r
+ Idx = PciHdr->Device.InterruptPin - 1;\r
+ while (!IsDevicePathEnd (DevPathNode)) {\r
+ if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&\r
+ DevicePathSubType (DevPathNode) == HW_PCI_DP) {\r
+\r
+ Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
+\r
+ //\r
+ // Unlike SeaBIOS, which starts climbing from the leaf device\r
+ // up toward the root, we traverse the device path starting at\r
+ // the root moving toward the leaf node.\r
+ // The slot number of the top-level parent bridge is needed for\r
+ // Q35 cases with more than 24 slots on the root bus.\r
+ //\r
+ if (Status != EFI_SUCCESS) {\r
+ Status = EFI_SUCCESS;\r
+ RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;\r
+ }\r
+ }\r
+\r
+ DevPathNode = NextDevicePathNode (DevPathNode);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (RootBusNumber == 0 && RootSlot == 0) {\r
+ DEBUG((\r
+ DEBUG_ERROR,\r
+ "%a: PCI host bridge (00:00.0) should have no interrupts!\n",\r
+ __FUNCTION__\r
+ ));\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ //\r
+ // Final PciHostIrqs[] index calculation depends on the platform\r
+ // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()\r
+ //\r
+ switch (mHostBridgeDevId) {\r
+ case INTEL_82441_DEVICE_ID:\r
+ Idx -= 1;\r
+ break;\r
+ case INTEL_Q35_MCH_DEVICE_ID:\r
+ //\r
+ // SeaBIOS contains the following comment:\r
+ // "Slots 0-24 rotate slot:pin mapping similar to piix above, but\r
+ // with a different starting index - see q35-acpi-dsdt.dsl.\r
+ //\r
+ // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"\r
+ //\r
+ if (RootSlot > 24) {\r
+ //\r
+ // in this case, subtract back out RootSlot from Idx\r
+ // (SeaBIOS never adds it to begin with, but that would make our\r
+ // device path traversal loop above too awkward)\r
+ //\r
+ Idx -= RootSlot;\r
+ }\r
+ break;\r
+ default:\r
+ ASSERT (FALSE); // should never get here\r
+ }\r
+ Idx %= ARRAY_SIZE (PciHostIrqs);\r
+ IrqLine = PciHostIrqs[Idx];\r
+\r
+ DEBUG_CODE_BEGIN ();\r
+ {\r
+ CHAR16 *DevPathString;\r
+ STATIC CHAR16 Fallback[] = L"<failed to convert>";\r
+ UINTN Segment, Bus, Device, Function;\r
+\r
+ DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);\r
+ if (DevPathString == NULL) {\r
+ DevPathString = Fallback;\r
+ }\r
+ Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,\r
+ (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,\r
+ IrqLine));\r
+\r
+ if (DevPathString != Fallback) {\r
+ FreePool (DevPathString);\r
+ }\r
+ }\r
+ DEBUG_CODE_END ();\r
+\r
+ //\r
+ // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]\r
+ //\r
+ Status = PciIo->Pci.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ PCI_INT_LINE_OFFSET,\r
+ 1,\r
+ &IrqLine\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+VOID\r
+PciAcpiInitialization (\r
+ )\r
+{\r
+ UINTN Pmba;\r
+\r
+ //\r
+ // Query Host Bridge DID to determine platform type\r
+ //\r
+ mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
+ switch (mHostBridgeDevId) {\r
+ case INTEL_82441_DEVICE_ID:\r
+ Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);\r
+ //\r
+ // 00:01.0 ISA Bridge (PIIX4) LNK routing targets\r
+ //\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D\r
+ break;\r
+ case INTEL_Q35_MCH_DEVICE_ID:\r
+ Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);\r
+ //\r
+ // 00:1f.0 LPC Bridge (Q35) LNK routing targets\r
+ //\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G\r
+ PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H\r
+ break;\r
+ default:\r
+ DEBUG ((DEBUG_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
+ __FUNCTION__, mHostBridgeDevId));\r
+ ASSERT (FALSE);\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices\r
+ //\r
+ VisitAllPciInstances (SetPciIntLine);\r
+\r
+ //\r
+ // Set ACPI SCI_EN bit in PMCNTRL\r
+ //\r
+ IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+ConnectRecursivelyIfPciMassStorage (\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_PCI_IO_PROTOCOL *Instance,\r
+ IN PCI_TYPE00 *PciHeader\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ CHAR16 *DevPathStr;\r
+\r
+ //\r
+ // Recognize PCI Mass Storage\r
+ //\r
+ if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {\r
+ DevicePath = NULL;\r
+ Status = gBS->HandleProtocol (\r
+ Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID*)&DevicePath\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Print Device Path\r
+ //\r
+ DevPathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
+ if (DevPathStr != NULL) {\r
+ DEBUG((\r
+ DEBUG_INFO,\r
+ "Found Mass Storage device: %s\n",\r
+ DevPathStr\r
+ ));\r
+ FreePool(DevPathStr);\r
+ }\r
+\r
+ Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Connect with predefined platform connect sequence.\r
+\r
+ The OEM/IBV can customize with their own connect sequence.\r
+**/\r
+VOID\r
+PlatformBdsConnectSequence (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ DEBUG ((DEBUG_INFO, "PlatformBdsConnectSequence\n"));\r
+\r
+ Index = 0;\r
+\r
+ //\r
+ // Here we can get the customized platform connect sequence\r
+ // Notes: we can connect with new variable which record the\r
+ // last time boots connect device path sequence\r
+ //\r
+ while (gPlatformConnectSequence[Index] != NULL) {\r
+ //\r
+ // Build the platform boot option\r
+ //\r
+ EfiBootManagerConnectDevicePath (gPlatformConnectSequence[Index], NULL);\r
+ Index++;\r
+ }\r
+ EfiBootManagerConnectAll ();\r
+}\r
+\r
+/**\r
+ Do the platform specific action after the console is ready\r
+\r
+ Possible things that can be done in PlatformBootManagerAfterConsole:\r
+\r
+ > Console post action:\r
+ > Dynamically switch output mode from 100x31 to 80x25 for certain senarino\r
+ > Signal console ready platform customized event\r
+ > Run diagnostics like memory testing\r
+ > Connect certain devices\r
+ > Dispatch aditional option roms\r
+ > Special boot: e.g.: USB boot, enter UI\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformBootManagerAfterConsole (\r
+ VOID\r
+ )\r
+{\r
+ EFI_BOOT_MODE BootMode;\r
+\r
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n"));\r
+\r
+ //\r
+ // Get current Boot Mode\r
+ //\r
+ BootMode = GetBootModeHob ();\r
+ DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));\r
+\r
+ //\r
+ // Go the different platform policy with different boot mode\r
+ // Notes: this part code can be change with the table policy\r
+ //\r
+ ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);\r
+\r
+ //\r
+ // Logo show\r
+ //\r
+ BootLogoEnableLogo ();\r
+\r
+ //\r
+ // Set PCI Interrupt Line registers and ACPI SCI_EN\r
+ //\r
+ PciAcpiInitialization ();\r
+\r
+ //\r
+ // Process TPM PPI request\r
+ //\r
+ Tcg2PhysicalPresenceLibProcessRequest (NULL);\r
+\r
+ //\r
+ // Perform some platform specific connect sequence\r
+ //\r
+ PlatformBdsConnectSequence ();\r
+\r
+ EfiBootManagerRefreshAllBootOption ();\r
+\r
+ //\r
+ // Register UEFI Shell (Will be removed if the Shell isn't built\r
+ // which is the default)\r
+ //\r
+ PlatformRegisterFvBootOption (\r
+ &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE\r
+ );\r
+\r
+ //\r
+ // Register Grub\r
+ //\r
+ PlatformRegisterFvBootOption (\r
+ &gGrubFileGuid, L"Grub Bootloader", LOAD_OPTION_ACTIVE\r
+ );\r
+\r
+ RemoveStaleFvFileOptions ();\r
+\r
+ PlatformBmPrintScRegisterHandler ();\r
+}\r
+\r
+/**\r
+ This notification function is invoked when an instance of the\r
+ EFI_DEVICE_PATH_PROTOCOL is produced.\r
+\r
+ @param Event The event that occurred\r
+ @param Context For EFI compatibility. Not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+NotifyDevPath (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_HANDLE Handle;\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevPathNode;\r
+ ATAPI_DEVICE_PATH *Atapi;\r
+\r
+ //\r
+ // Examine all new handles\r
+ //\r
+ for (;;) {\r
+ //\r
+ // Get the next handle\r
+ //\r
+ BufferSize = sizeof (Handle);\r
+ Status = gBS->LocateHandle (\r
+ ByRegisterNotify,\r
+ NULL,\r
+ mEfiDevPathNotifyReg,\r
+ &BufferSize,\r
+ &Handle\r
+ );\r
+\r
+ //\r
+ // If not found, we're done\r
+ //\r
+ if (EFI_NOT_FOUND == Status) {\r
+ break;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Get the DevicePath protocol on that handle\r
+ //\r
+ Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid,\r
+ (VOID **)&DevPathNode);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ while (!IsDevicePathEnd (DevPathNode)) {\r
+ //\r
+ // Find the handler to dump this device path node\r
+ //\r
+ if (\r
+ (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&\r
+ (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)\r
+ ) {\r
+ Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;\r
+ PciOr16 (\r
+ PCI_LIB_ADDRESS (\r
+ 0,\r
+ 1,\r
+ 1,\r
+ (Atapi->PrimarySecondary == 1) ? 0x42: 0x40\r
+ ),\r
+ BIT15\r
+ );\r
+ }\r
+\r
+ //\r
+ // Next device path node\r
+ //\r
+ DevPathNode = NextDevicePathNode (DevPathNode);\r
+ }\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+\r
+VOID\r
+InstallDevicePathCallback (\r
+ VOID\r
+ )\r
+{\r
+ DEBUG ((DEBUG_INFO, "Registered NotifyDevPath Event\n"));\r
+ mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (\r
+ &gEfiDevicePathProtocolGuid,\r
+ TPL_CALLBACK,\r
+ NotifyDevPath,\r
+ NULL,\r
+ &mEfiDevPathNotifyReg\r
+ );\r
+}\r
+\r
+/**\r
+ This function is called each second during the boot manager waits the\r
+ timeout.\r
+\r
+ @param TimeoutRemain The remaining timeout.\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformBootManagerWaitCallback (\r
+ UINT16 TimeoutRemain\r
+ )\r
+{\r
+ //\r
+ // Since the timeout should be forced to zero we should never\r
+ // Get here\r
+ //\r
+ ASSERT (FALSE);\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
+ //\r
+ // If we get here something failed about the grub boot but since\r
+ // We're privy to the secret we must panic and not retry or loop\r
+ //\r
+ ASSERT (FALSE);\r
+ CpuDeadLoop ();\r
+}\r