Some ConIn or ConOut device may not in the first root bridge, so connect all root bridge before detect ConIn and ConOut device. Reviewed-by: Guo Dong <guo.dong@intel.com> Reviewed-by: Ray Ni <ray.ni@intel.com> Cc: Maurice Ma <maurice.ma@intel.com> Cc: Benjamin You <benjamin.you@intel.com> Cc: Sean Rhodes <sean@starlabs.systems> Signed-off-by: Zhiguang Liu <zhiguang.liu@intel.com>
		
			
				
	
	
		
			480 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			480 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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);
 | 
						|
}
 |