/** @file This file include all platform action which can be customized by IBV/OEM. Copyright (c) 2016, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include "PlatformBootManager.h" #include "PlatformConsole.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 gUartVendor \ { \ { \ HARDWARE_DEVICE_PATH, \ HW_VENDOR_DP, \ { \ (UINT8) (sizeof (VENDOR_DEVICE_PATH)), \ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) \ } \ }, \ {0xD3987D4B, 0x971A, 0x435F, {0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41}} \ } #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 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 UART to ConOut, ConIn, ErrOut. @param[in] DeviceHandle - LPC device path. @retval EFI_SUCCESS - Serial console is added to ConOut, ConIn, and ErrOut. @retval EFI_STATUS - No serial console is added. **/ 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 COM1 // 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; ACPI_ADR_DEVICE_PATH AcpiAdr; EFI_DEVICE_PATH_PROTOCOL *MyDevicePath; if (PciDevicePath == NULL || GopDevicePath == NULL) { return EFI_INVALID_PARAMETER; } MyDevicePath = NULL; // // Initialize the GopDevicePath to be PciDevicePath // *GopDevicePath = PciDevicePath; TempPciDevicePath = PciDevicePath; Status = gBS->LocateDevicePath ( &gEfiDevicePathProtocolGuid, &TempPciDevicePath, &PciDeviceHandle ); if (EFI_ERROR (Status)) { return Status; } // // Try to connect this handle, so that GOP dirver could start on this // device and create child handles with GraphicsOutput Protocol installed // on them, then we get device paths of these child handles and select // them as possible console device. // AcpiAdr.Header.Type = ACPI_DEVICE_PATH; AcpiAdr.Header.SubType = ACPI_ADR_DP; AcpiAdr.ADR= ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_INTERNAL_DIGITAL, 8, 0); SetDevicePathNodeLength (&AcpiAdr.Header, sizeof (ACPI_ADR_DEVICE_PATH)); MyDevicePath = AppendDevicePathNode(MyDevicePath, (EFI_DEVICE_PATH_PROTOCOL*)&AcpiAdr); gBS->ConnectController (PciDeviceHandle, NULL, MyDevicePath, FALSE); FreePool(MyDevicePath); 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 futhure, 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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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; 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); }