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