| /** @file | |
| This file include all platform action which can be customized by IBV/OEM. | |
| Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "PlatformBootManager.h" | |
| #include "PlatformConsole.h" | |
| #include <Guid/SerialPortLibVendor.h> | |
| #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 gPnp16550ComPort \ | |
| PNPID_DEVICE_PATH_NODE(0x0501) | |
| #define gPnpPs2Keyboard \ | |
| PNPID_DEVICE_PATH_NODE(0x0303) | |
| #define gPcAnsiTerminal \ | |
| { \ | |
| { \ | |
| MESSAGING_DEVICE_PATH, \ | |
| MSG_VENDOR_DP, \ | |
| { \ | |
| (UINT8) (sizeof (VENDOR_DEVICE_PATH)), \ | |
| (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) \ | |
| } \ | |
| }, \ | |
| DEVICE_PATH_MESSAGING_PC_ANSI \ | |
| } | |
| ACPI_HID_DEVICE_PATH gPnpPs2KeyboardDeviceNode = gPnpPs2Keyboard; | |
| ACPI_HID_DEVICE_PATH gPnp16550ComPortDeviceNode = gPnp16550ComPort; | |
| VENDOR_DEVICE_PATH gTerminalTypeDeviceNode = gPcAnsiTerminal; | |
| BOOLEAN mDetectDisplayOnly; | |
| /** | |
| Add IsaKeyboard to ConIn. | |
| @param[in] DeviceHandle Handle of the LPC Bridge device. | |
| @retval EFI_SUCCESS IsaKeyboard on the LPC bridge have been added to ConIn. | |
| @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; | |
| DevicePath = NULL; | |
| Status = gBS->HandleProtocol ( | |
| DeviceHandle, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID *)&DevicePath | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Register Keyboard | |
| // | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode); | |
| EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Return the GOP device path in the platform. | |
| @param[in] PciDevicePath - Device path for the PCI graphics device. | |
| @param[out] GopDevicePath - Return the device path with GOP installed. | |
| @retval EFI_SUCCESS - PCI VGA is added to ConOut. | |
| @retval EFI_INVALID_PARAMETER - The device path parameter is invalid. | |
| @retval EFI_STATUS - No GOP device found. | |
| **/ | |
| 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; | |
| } | |
| 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 (ConOut, NULL, PciDevicePath); | |
| EfiBootManagerUpdateConsoleVariable (ConOut, TempDevicePath, NULL); | |
| } | |
| } | |
| gBS->FreePool (GopHandleBuffer); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Add PCI VGA to ConOut, ConIn, ErrOut. | |
| @param[in] DeviceHandle - Handle of PciIo protocol. | |
| @retval EFI_SUCCESS - PCI VGA is added to ConOut. | |
| @retval EFI_STATUS - No PCI VGA device is added. | |
| **/ | |
| EFI_STATUS | |
| PreparePciVgaDevicePath ( | |
| IN EFI_HANDLE DeviceHandle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *GopDevicePath; | |
| DevicePath = 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; | |
| } | |
| /** | |
| For every PCI instance execute a callback function. | |
| @param[in] Id - The protocol GUID for callback | |
| @param[in] CallBackFunction - The callback function | |
| @retval EFI_STATUS - Callback function failed. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| VisitAllInstancesOfProtocol ( | |
| IN EFI_GUID *Id, | |
| IN SIMPLE_PROTOCOL_INSTANCE_CALLBACK CallBackFunction | |
| ) | |
| { | |
| 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 | |
| ); | |
| } | |
| gBS->FreePool (HandleBuffer); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Do platform specific PCI Device check and add them to | |
| ConOut, ConIn, ErrOut. | |
| @param[in] Handle - Handle of PCI device instance | |
| @param[in] Instance - The instance of PCI device | |
| @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 VOID *Instance | |
| ) | |
| { | |
| 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; | |
| } | |
| Status = PciIo->Attributes ( | |
| PciIo, | |
| EfiPciIoAttributeOperationEnable, | |
| EFI_PCI_DEVICE_ENABLE, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| if (!mDetectDisplayOnly) { | |
| // | |
| // Here we decide whether it is LPC Bridge | |
| // | |
| if ((IS_PCI_LPC (&Pci)) || | |
| ((IS_PCI_ISA_PDECODE (&Pci)) && | |
| (Pci.Hdr.VendorId == 0x8086) | |
| ) | |
| ) | |
| { | |
| // | |
| // Add IsaKeyboard to ConIn, | |
| // add IsaSerial to ConOut, ConIn, ErrOut | |
| // | |
| DEBUG ((DEBUG_INFO, "Found LPC Bridge device\n")); | |
| PrepareLpcBridgeDevicePath (Handle); | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| // | |
| // Enable all display devices | |
| // | |
| if (IS_PCI_DISPLAY (&Pci)) { | |
| // | |
| // Add them to ConOut. | |
| // | |
| DEBUG ((DEBUG_INFO, "Found PCI Display device\n")); | |
| EfiBootManagerConnectVideoController (Handle); | |
| return EFI_SUCCESS; | |
| } | |
| return Status; | |
| } | |
| /** | |
| For every Serial Io instance, add it to ConOut, ConIn, ErrOut. | |
| @param[in] Handle - The Serial Io device handle | |
| @param[in] Instance - The instance of the SerialIo protocol | |
| @retval EFI_STATUS - Callback function failed. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AddDevicePathForOneSerialIoInstance ( | |
| IN EFI_HANDLE Handle, | |
| IN VOID *Instance | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| DevicePath = NULL; | |
| Status = gBS->HandleProtocol ( | |
| Handle, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID *)&DevicePath | |
| ); | |
| DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode); | |
| EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL); | |
| EfiBootManagerUpdateConsoleVariable (ConIn, DevicePath, NULL); | |
| EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL); | |
| return Status; | |
| } | |
| /** | |
| Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut | |
| @param[in] DetectDisplayOnly - Only detect display device if it's TRUE. | |
| @retval EFI_SUCCESS - PCI Device check and Console variable update successfully. | |
| @retval EFI_STATUS - PCI Device check or Console variable update fail. | |
| **/ | |
| EFI_STATUS | |
| DetectAndPreparePlatformPciDevicePaths ( | |
| BOOLEAN DetectDisplayOnly | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| mDetectDisplayOnly = DetectDisplayOnly; | |
| EfiBootManagerUpdateConsoleVariable ( | |
| ConIn, | |
| (EFI_DEVICE_PATH_PROTOCOL *)&gUsbClassKeyboardDevicePath, | |
| NULL | |
| ); | |
| VisitAllInstancesOfProtocol ( | |
| &gEfiSerialIoProtocolGuid, | |
| AddDevicePathForOneSerialIoInstance | |
| ); | |
| Status = VisitAllInstancesOfProtocol ( | |
| &gEfiPciIoProtocolGuid, | |
| DetectAndPreparePlatformPciDevicePath | |
| ); | |
| return Status; | |
| } | |
| /** | |
| The function will connect one root bridge | |
| @param[in] Handle - The root bridge handle | |
| @param[in] Instance - The instance of the root bridge | |
| @return EFI_SUCCESS Connect RootBridge successfully. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ConnectOneRootBridge ( | |
| IN EFI_HANDLE Handle, | |
| IN VOID *Instance | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = gBS->ConnectController (Handle, NULL, NULL, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Platform console init. Include the platform firmware vendor, revision | |
| and so crc check. | |
| **/ | |
| VOID | |
| EFIAPI | |
| PlatformConsoleInit ( | |
| VOID | |
| ) | |
| { | |
| VisitAllInstancesOfProtocol ( | |
| &gEfiPciRootBridgeIoProtocolGuid, | |
| ConnectOneRootBridge | |
| ); | |
| // | |
| // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut | |
| // | |
| DetectAndPreparePlatformPciDevicePaths (FALSE); | |
| } |