/** @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); | |
} |