/** @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 gPciRootBridge \ | |
PNPID_DEVICE_PATH_NODE(0x0A03) | |
#define gPnp16550ComPort \ | |
PNPID_DEVICE_PATH_NODE(0x0501) | |
#define gPnpPs2Keyboard \ | |
PNPID_DEVICE_PATH_NODE(0x0303) | |
#define gUartVendor \ | |
{ \ | |
{ \ | |
HARDWARE_DEVICE_PATH, \ | |
HW_VENDOR_DP, \ | |
{ \ | |
(UINT8) (sizeof (VENDOR_DEVICE_PATH)), \ | |
(UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) \ | |
} \ | |
}, \ | |
EDKII_SERIAL_PORT_LIB_VENDOR_GUID \ | |
} | |
#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 \ | |
} | |
ACPI_HID_DEVICE_PATH gPnpPs2KeyboardDeviceNode = gPnpPs2Keyboard; | |
ACPI_HID_DEVICE_PATH gPnp16550ComPortDeviceNode = gPnp16550ComPort; | |
UART_DEVICE_PATH gUartDeviceNode = gUart; | |
VENDOR_DEVICE_PATH gTerminalTypeDeviceNode = gPcAnsiTerminal; | |
VENDOR_DEVICE_PATH gUartDeviceVendorNode = gUartVendor; | |
// | |
// Predefined platform root bridge | |
// | |
PLATFORM_ROOT_BRIDGE_DEVICE_PATH gPlatformRootBridge0 = { | |
gPciRootBridge, | |
gEndEntire | |
}; | |
EFI_DEVICE_PATH_PROTOCOL *gPlatformRootBridges[] = { | |
(EFI_DEVICE_PATH_PROTOCOL *) &gPlatformRootBridge0, | |
NULL | |
}; | |
BOOLEAN mDetectVgaOnly; | |
/** | |
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; | |
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; | |
DevicePath = AppendDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *)NULL, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceVendorNode); | |
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; | |
} | |
/** | |
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; | |
} | |
/** | |
Add PCI Serial to ConOut, ConIn, ErrOut. | |
@param[in] DeviceHandle - Handle of PciIo protocol. | |
@retval EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut. | |
@retval EFI_STATUS - No PCI Serial device is added. | |
**/ | |
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; | |
} | |
/** | |
For every PCI instance execute a callback function. | |
@param[in] Id - The protocol GUID for callback | |
@param[in] CallBackFunction - The callback function | |
@param[in] Context - The context of the callback | |
@retval EFI_STATUS - Callback function failed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
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; | |
} | |
/** | |
For every PCI instance execute a callback function. | |
@param[in] Handle - The PCI device handle | |
@param[in] Instance - The instance of the PciIo protocol | |
@param[in] Context - The context of the callback | |
@retval EFI_STATUS - Callback function failed. | |
**/ | |
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 | |
); | |
} | |
/** | |
For every PCI instance execute a callback function. | |
@param[in] CallBackFunction - Callback function pointer | |
@retval EFI_STATUS - Callback function failed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
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); | |
if (!mDetectVgaOnly) { | |
// | |
// 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; | |
} | |
// | |
// 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 VGA device to enable in PCI bus | |
// | |
if (IS_PCI_VGA (Pci)) { | |
// | |
// Add them to ConOut. | |
// | |
DEBUG ((DEBUG_INFO, "Found PCI VGA device\n")); | |
PreparePciVgaDevicePath (Handle); | |
return EFI_SUCCESS; | |
} | |
return Status; | |
} | |
/** | |
Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut | |
@param[in] DetectVgaOnly - Only detect VGA 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 DetectVgaOnly | |
) | |
{ | |
mDetectVgaOnly = DetectVgaOnly; | |
EfiBootManagerUpdateConsoleVariable ( | |
ConIn, | |
(EFI_DEVICE_PATH_PROTOCOL *) &gUsbClassKeyboardDevicePath, | |
NULL | |
); | |
return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath); | |
} | |
/** | |
The function will connect root bridge | |
@return EFI_SUCCESS Connect RootBridge successfully. | |
**/ | |
EFI_STATUS | |
ConnectRootBridge ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE RootHandle; | |
// | |
// Make all the PCI_IO protocols on PCI Seg 0 show up | |
// | |
Status = gBS->LocateDevicePath ( | |
&gEfiDevicePathProtocolGuid, | |
&gPlatformRootBridges[0], | |
&RootHandle | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = gBS->ConnectController (RootHandle, 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 | |
) | |
{ | |
gUartDeviceNode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate); | |
gUartDeviceNode.DataBits = PcdGet8 (PcdUartDefaultDataBits); | |
gUartDeviceNode.Parity = PcdGet8 (PcdUartDefaultParity); | |
gUartDeviceNode.StopBits = PcdGet8 (PcdUartDefaultStopBits); | |
ConnectRootBridge (); | |
// | |
// Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut | |
// | |
DetectAndPreparePlatformPciDevicePaths (FALSE); | |
} |