/** @file
This file include all platform action which can be customized by IBV/OEM.
Copyright (c) 2016, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "PlatformBootManager.h"
#include "PlatformConsole.h"
#include
#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);
}