audk/CorebootPayloadPkg/FbGop/FbGop.c

1537 lines
47 KiB
C

/** @file
ConsoleOut Routines that speak VGA.
Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "FbGop.h"
EFI_PIXEL_BITMASK mPixelBitMask = {0x0000FF, 0x00FF00, 0xFF0000, 0x000000};
//
// Save controller attributes during first start
//
UINT64 mOriginalPciAttributes;
BOOLEAN mPciAttributesSaved = FALSE;
FRAME_BUFFER_INFO *mFrameBufferInfo;
//
// EFI Driver Binding Protocol Instance
//
EFI_DRIVER_BINDING_PROTOCOL gFbGopDriverBinding = {
FbGopDriverBindingSupported,
FbGopDriverBindingStart,
FbGopDriverBindingStop,
0x3,
NULL,
NULL
};
//
// Native resolution in EDID DetailedTiming[0]
//
UINT32 mNativeModeHorizontal;
UINT32 mNativeModeVertical;
/**
Supported.
@param This Pointer to driver binding protocol
@param Controller Controller handle to connect
@param RemainingDevicePath A pointer to the remaining portion of a device
path
@retval EFI_STATUS EFI_SUCCESS:This controller can be managed by this
driver, Otherwise, this controller cannot be
managed by this driver
**/
EFI_STATUS
EFIAPI
FbGopDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
PCI_TYPE00 Pci;
EFI_DEV_PATH *Node;
UINT8 Index;
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;
//
// Open the IO Abstraction(s) needed to perform the supported test
//
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// See if this is a PCI Graphics Controller by looking at the Command register and
// Class Code Register
//
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint32,
0,
sizeof (Pci) / sizeof (UINT32),
&Pci
);
if (EFI_ERROR (Status)) {
Status = EFI_UNSUPPORTED;
goto Done;
}
Status = EFI_UNSUPPORTED;
if (IS_PCI_DISPLAY (&Pci) || IS_PCI_OLD_VGA (&Pci)) {
//
// Check if PCI BAR matches the framebuffer base
//
Status = EFI_UNSUPPORTED;
for (Index = 0; Index < PCI_MAX_BAR; Index++) {
Status = PciIo->GetBarAttributes (PciIo, Index, NULL, (VOID**) &Resources);
if (!EFI_ERROR (Status)) {
if ((Resources->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) &&
(Resources->Len == (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3)) &&
(Resources->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) &&
(Resources->AddrRangeMin == mFrameBufferInfo->LinearFrameBuffer)) {
DEBUG ((DEBUG_INFO, "Found matched framebuffer PCI BAR !\n"));
Status = EFI_SUCCESS;
break;
}
}
}
if (!EFI_ERROR (Status)) {
//
// If this is a graphics controller,
// go further check RemainingDevicePath
//
if (RemainingDevicePath != NULL) {
Node = (EFI_DEV_PATH *) RemainingDevicePath;
//
// Check if RemainingDevicePath is the End of Device Path Node,
// if yes, return EFI_SUCCESS
//
if (!IsDevicePathEnd (Node)) {
//
// Verify RemainingDevicePath
//
if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
Node->DevPath.SubType != ACPI_ADR_DP ||
DevicePathNodeLength(&Node->DevPath) < sizeof(ACPI_ADR_DEVICE_PATH)) {
Status = EFI_UNSUPPORTED;
}
}
}
}
}
Done:
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
return Status;
}
/**
Install Graphics Output Protocol onto VGA device handles.
@param This Pointer to driver binding protocol
@param Controller Controller handle to connect
@param RemainingDevicePath A pointer to the remaining portion of a device
path
@return EFI_STATUS
**/
EFI_STATUS
EFIAPI
FbGopDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
EFI_PCI_IO_PROTOCOL *PciIo;
UINT64 Supports;
DEBUG ((DEBUG_INFO, "GOP START\n"));
//
// Initialize local variables
//
PciIo = NULL;
ParentDevicePath = NULL;
//
// Prepare for status code
//
Status = gBS->HandleProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
(VOID **) &ParentDevicePath
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Open the IO Abstraction(s) needed
//
Status = gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
return Status;
}
//
// Save original PCI attributes
//
if (!mPciAttributesSaved) {
Status = PciIo->Attributes (
PciIo,
EfiPciIoAttributeOperationGet,
0,
&mOriginalPciAttributes
);
if (EFI_ERROR (Status)) {
goto Done;
}
mPciAttributesSaved = TRUE;
}
//
// Get supported PCI attributes
//
Status = PciIo->Attributes (
PciIo,
EfiPciIoAttributeOperationSupported,
0,
&Supports
);
if (EFI_ERROR (Status)) {
goto Done;
}
Supports &= (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {
Status = EFI_UNSUPPORTED;
goto Done;
}
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_PROGRESS_CODE,
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE,
ParentDevicePath
);
//
// Enable the device and make sure VGA cycles are being forwarded to this VGA device
//
Status = PciIo->Attributes (
PciIo,
EfiPciIoAttributeOperationEnable,
EFI_PCI_DEVICE_ENABLE,
NULL
);
if (EFI_ERROR (Status)) {
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_ERROR_CODE | EFI_ERROR_MINOR,
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_RESOURCE_CONFLICT,
ParentDevicePath
);
goto Done;
}
if (RemainingDevicePath != NULL) {
if (IsDevicePathEnd (RemainingDevicePath)) {
//
// If RemainingDevicePath is the End of Device Path Node,
// don't create any child device and return EFI_SUCCESS
Status = EFI_SUCCESS;
goto Done;
}
}
//
// Create child handle and install GraphicsOutputProtocol on it
//
Status = FbGopChildHandleInstall (
This,
Controller,
PciIo,
NULL,
ParentDevicePath,
RemainingDevicePath
);
Done:
if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_PROGRESS_CODE,
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE,
ParentDevicePath
);
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_PROGRESS_CODE,
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_NOT_DETECTED,
ParentDevicePath
);
if (!HasChildHandle (Controller)) {
if (mPciAttributesSaved) {
//
// Restore original PCI attributes
//
PciIo->Attributes (
PciIo,
EfiPciIoAttributeOperationSet,
mOriginalPciAttributes,
NULL
);
}
}
//
// Release PCI I/O Protocols on the controller handle.
//
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
}
return Status;
}
/**
Stop.
@param This Pointer to driver binding protocol
@param Controller Controller handle to connect
@param NumberOfChildren Number of children handle created by this driver
@param ChildHandleBuffer Buffer containing child handle created
@retval EFI_SUCCESS Driver disconnected successfully from controller
@retval EFI_UNSUPPORTED Cannot find FB_VIDEO_DEV structure
**/
EFI_STATUS
EFIAPI
FbGopDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_STATUS Status;
BOOLEAN AllChildrenStopped;
UINTN Index;
EFI_PCI_IO_PROTOCOL *PciIo;
AllChildrenStopped = TRUE;
if (NumberOfChildren == 0) {
//
// Close PCI I/O protocol on the controller handle
//
gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Controller
);
return EFI_SUCCESS;
}
for (Index = 0; Index < NumberOfChildren; Index++) {
Status = EFI_SUCCESS;
FbGopChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]);
if (EFI_ERROR (Status)) {
AllChildrenStopped = FALSE;
}
}
if (!AllChildrenStopped) {
return EFI_DEVICE_ERROR;
}
if (!HasChildHandle (Controller)) {
if (mPciAttributesSaved) {
Status = gBS->HandleProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo
);
ASSERT_EFI_ERROR (Status);
//
// Restore original PCI attributes
//
Status = PciIo->Attributes (
PciIo,
EfiPciIoAttributeOperationSet,
mOriginalPciAttributes,
NULL
);
ASSERT_EFI_ERROR (Status);
}
}
return EFI_SUCCESS;
}
/**
Install child handles if the Handle supports MBR format.
@param This Calling context.
@param ParentHandle Parent Handle
@param ParentPciIo Parent PciIo interface
@param ParentLegacyBios Parent LegacyBios interface
@param ParentDevicePath Parent Device Path
@param RemainingDevicePath Remaining Device Path
@retval EFI_SUCCESS If a child handle was added
@retval other A child handle was not added
**/
EFI_STATUS
FbGopChildHandleInstall (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ParentHandle,
IN EFI_PCI_IO_PROTOCOL *ParentPciIo,
IN VOID *ParentLegacyBios,
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
FB_VIDEO_DEV *FbGopPrivate;
PCI_TYPE00 Pci;
ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
//
// Allocate the private device structure for video device
//
FbGopPrivate = (FB_VIDEO_DEV *) AllocateZeroPool (
sizeof (FB_VIDEO_DEV)
);
if (NULL == FbGopPrivate) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
//
// See if this is a VGA compatible controller or not
//
Status = ParentPciIo->Pci.Read (
ParentPciIo,
EfiPciIoWidthUint32,
0,
sizeof (Pci) / sizeof (UINT32),
&Pci
);
if (EFI_ERROR (Status)) {
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
EFI_ERROR_CODE | EFI_ERROR_MINOR,
EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
ParentDevicePath
);
goto Done;
}
//
// Initialize the child private structure
//
FbGopPrivate->Signature = FB_VIDEO_DEV_SIGNATURE;
//
// Fill in Graphics Output specific mode structures
//
FbGopPrivate->ModeData = NULL;
FbGopPrivate->VbeFrameBuffer = NULL;
FbGopPrivate->EdidDiscovered.SizeOfEdid = 0;
FbGopPrivate->EdidDiscovered.Edid = NULL;
FbGopPrivate->EdidActive.SizeOfEdid = 0;
FbGopPrivate->EdidActive.Edid = NULL;
//
// Fill in the Graphics Output Protocol
//
FbGopPrivate->GraphicsOutput.QueryMode = FbGopGraphicsOutputQueryMode;
FbGopPrivate->GraphicsOutput.SetMode = FbGopGraphicsOutputSetMode;
//
// Allocate buffer for Graphics Output Protocol mode information
//
FbGopPrivate->GraphicsOutput.Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *) AllocatePool (
sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)
);
if (NULL == FbGopPrivate->GraphicsOutput.Mode) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
FbGopPrivate->GraphicsOutput.Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
);
if (NULL == FbGopPrivate->GraphicsOutput.Mode->Info) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
//
// Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node.
//
if ((RemainingDevicePath == NULL) || (!IsDevicePathEnd (RemainingDevicePath))) {
if (RemainingDevicePath == NULL) {
ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
FbGopPrivate->GopDevicePath = AppendDevicePathNode (
ParentDevicePath,
(EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
);
} else {
FbGopPrivate->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
}
//
// Creat child handle and device path protocol firstly
//
FbGopPrivate->Handle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&FbGopPrivate->Handle,
&gEfiDevicePathProtocolGuid,
FbGopPrivate->GopDevicePath,
NULL
);
if (EFI_ERROR (Status)) {
goto Done;
}
}
//
// When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally
//
FbGopPrivate->PciIo = ParentPciIo;
//
// Check for VESA BIOS Extensions for modes that are compatible with Graphics Output
//
Status = FbGopCheckForVbe (FbGopPrivate);
DEBUG ((DEBUG_INFO, "FbGopCheckForVbe - %r\n", Status));
if (EFI_ERROR (Status)) {
Status = EFI_UNSUPPORTED;
//goto Done;
}
//
// Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol
//
Status = gBS->InstallMultipleProtocolInterfaces (
&FbGopPrivate->Handle,
&gEfiGraphicsOutputProtocolGuid,
&FbGopPrivate->GraphicsOutput,
&gEfiEdidDiscoveredProtocolGuid,
&FbGopPrivate->EdidDiscovered,
&gEfiEdidActiveProtocolGuid,
&FbGopPrivate->EdidActive,
NULL
);
if (!EFI_ERROR (Status)) {
//
// Open the Parent Handle for the child
//
Status = gBS->OpenProtocol (
ParentHandle,
&gEfiPciIoProtocolGuid,
(VOID **) &FbGopPrivate->PciIo,
This->DriverBindingHandle,
FbGopPrivate->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
goto Done;
}
}
Done:
if (EFI_ERROR (Status)) {
//
// Free private data structure
//
FbGopDeviceReleaseResource (FbGopPrivate);
}
return Status;
}
/**
Deregister an video child handle and free resources.
@param This Protocol instance pointer.
@param Controller Video controller handle
@param Handle Video child handle
@return EFI_STATUS
**/
EFI_STATUS
FbGopChildHandleUninstall (
EFI_DRIVER_BINDING_PROTOCOL *This,
EFI_HANDLE Controller,
EFI_HANDLE Handle
)
{
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
FB_VIDEO_DEV *FbGopPrivate;
EFI_PCI_IO_PROTOCOL *PciIo;
FbGopPrivate = NULL;
GraphicsOutput = NULL;
PciIo = NULL;
Status = EFI_UNSUPPORTED;
Status = gBS->OpenProtocol (
Handle,
&gEfiGraphicsOutputProtocolGuid,
(VOID **) &GraphicsOutput,
This->DriverBindingHandle,
Handle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR (Status)) {
FbGopPrivate = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
}
if (FbGopPrivate == NULL) {
return EFI_UNSUPPORTED;
}
//
// Close PCI I/O protocol that opened by child handle
//
Status = gBS->CloseProtocol (
Controller,
&gEfiPciIoProtocolGuid,
This->DriverBindingHandle,
Handle
);
//
// Uninstall protocols on child handle
//
Status = gBS->UninstallMultipleProtocolInterfaces (
FbGopPrivate->Handle,
&gEfiDevicePathProtocolGuid,
FbGopPrivate->GopDevicePath,
&gEfiGraphicsOutputProtocolGuid,
&FbGopPrivate->GraphicsOutput,
NULL
);
if (EFI_ERROR (Status)) {
gBS->OpenProtocol (
Controller,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo,
This->DriverBindingHandle,
Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
return Status;
}
//
// Release all allocated resources
//
FbGopDeviceReleaseResource (FbGopPrivate);
return EFI_SUCCESS;
}
/**
Release resource for bios video instance.
@param FbGopPrivate Video child device private data structure
**/
VOID
FbGopDeviceReleaseResource (
FB_VIDEO_DEV *FbGopPrivate
)
{
if (FbGopPrivate == NULL) {
return ;
}
//
// Release all the resources occupied by the FB_VIDEO_DEV
//
//
// Free VBE Frame Buffer
//
if (FbGopPrivate->VbeFrameBuffer != NULL) {
FreePool (FbGopPrivate->VbeFrameBuffer);
}
//
// Free mode data
//
if (FbGopPrivate->ModeData != NULL) {
FreePool (FbGopPrivate->ModeData);
}
//
// Free graphics output protocol occupied resource
//
if (FbGopPrivate->GraphicsOutput.Mode != NULL) {
if (FbGopPrivate->GraphicsOutput.Mode->Info != NULL) {
FreePool (FbGopPrivate->GraphicsOutput.Mode->Info);
FbGopPrivate->GraphicsOutput.Mode->Info = NULL;
}
FreePool (FbGopPrivate->GraphicsOutput.Mode);
FbGopPrivate->GraphicsOutput.Mode = NULL;
}
if (FbGopPrivate->GopDevicePath!= NULL) {
FreePool (FbGopPrivate->GopDevicePath);
}
FreePool (FbGopPrivate);
return ;
}
/**
Check if all video child handles have been uninstalled.
@param Controller Video controller handle
@return TRUE Child handles exist.
@return FALSE All video child handles have been uninstalled.
**/
BOOLEAN
HasChildHandle (
IN EFI_HANDLE Controller
)
{
UINTN Index;
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
UINTN EntryCount;
BOOLEAN HasChild;
EntryCount = 0;
HasChild = FALSE;
gBS->OpenProtocolInformation (
Controller,
&gEfiPciIoProtocolGuid,
&OpenInfoBuffer,
&EntryCount
);
for (Index = 0; Index < EntryCount; Index++) {
if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
HasChild = TRUE;
}
}
return HasChild;
}
/**
Check for VBE device.
@param FbGopPrivate Pointer to FB_VIDEO_DEV structure
@retval EFI_SUCCESS VBE device found
**/
EFI_STATUS
FbGopCheckForVbe (
IN OUT FB_VIDEO_DEV *FbGopPrivate
)
{
EFI_STATUS Status;
FB_VIDEO_MODE_DATA *ModeBuffer;
FB_VIDEO_MODE_DATA *CurrentModeData;
UINTN ModeNumber;
UINTN BitsPerPixel;
UINTN BytesPerScanLine;
UINT32 HorizontalResolution;
UINT32 VerticalResolution;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer;
FRAME_BUFFER_INFO *FbInfo;
Status = EFI_SUCCESS;
FbInfo = mFrameBufferInfo;
//
// Add mode to the list of available modes
//
VbeFrameBuffer = NULL;
ModeBuffer = NULL;
ModeNumber = 1;
BitsPerPixel = FbInfo->BitsPerPixel;
HorizontalResolution = FbInfo->HorizontalResolution;
VerticalResolution = FbInfo->VerticalResolution;
BytesPerScanLine = FbInfo->BytesPerScanLine;
ModeBuffer = (FB_VIDEO_MODE_DATA *) AllocatePool (
ModeNumber * sizeof (FB_VIDEO_MODE_DATA)
);
if (NULL == ModeBuffer) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
VbeFrameBuffer =
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool (
BytesPerScanLine * VerticalResolution
);
if (NULL == VbeFrameBuffer) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
if (FbGopPrivate->ModeData != NULL) {
FreePool (FbGopPrivate->ModeData);
}
if (FbGopPrivate->VbeFrameBuffer != NULL) {
FreePool (FbGopPrivate->VbeFrameBuffer);
}
CurrentModeData = &ModeBuffer[ModeNumber - 1];
CurrentModeData->BytesPerScanLine = (UINT16)BytesPerScanLine;
CurrentModeData->Red = *(FB_VIDEO_COLOR_PLACEMENT *)&(FbInfo->Red);
CurrentModeData->Blue = *(FB_VIDEO_COLOR_PLACEMENT *)&(FbInfo->Blue);
CurrentModeData->Green = *(FB_VIDEO_COLOR_PLACEMENT *)&(FbInfo->Green);
CurrentModeData->Reserved = *(FB_VIDEO_COLOR_PLACEMENT *)&(FbInfo->Reserved);
CurrentModeData->BitsPerPixel = (UINT32)BitsPerPixel;
CurrentModeData->HorizontalResolution = HorizontalResolution;
CurrentModeData->VerticalResolution = VerticalResolution;
CurrentModeData->FrameBufferSize = CurrentModeData->BytesPerScanLine * CurrentModeData->VerticalResolution;
CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN) FbInfo->LinearFrameBuffer;
CurrentModeData->VbeModeNumber = 0;
CurrentModeData->ColorDepth = 32;
CurrentModeData->RefreshRate = 60;
CurrentModeData->PixelFormat = PixelBitMask;
if ((CurrentModeData->BitsPerPixel == 32) &&
(CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) {
if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) {
CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
} else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) {
CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
}
}
CopyMem (&(CurrentModeData->PixelBitMask), &mPixelBitMask, sizeof (EFI_PIXEL_BITMASK));
FbGopPrivate->ModeData = ModeBuffer;
FbGopPrivate->VbeFrameBuffer = VbeFrameBuffer;
//
// Assign Gop's Blt function
//
FbGopPrivate->GraphicsOutput.Blt = FbGopGraphicsOutputVbeBlt;
FbGopPrivate->GraphicsOutput.Mode->MaxMode = 1;
FbGopPrivate->GraphicsOutput.Mode->Mode = 0;
FbGopPrivate->GraphicsOutput.Mode->Info->Version = 0;
FbGopPrivate->GraphicsOutput.Mode->Info->HorizontalResolution = HorizontalResolution;
FbGopPrivate->GraphicsOutput.Mode->Info->VerticalResolution = VerticalResolution;
FbGopPrivate->GraphicsOutput.Mode->Info->PixelFormat = CurrentModeData->PixelFormat;
CopyMem (&(FbGopPrivate->GraphicsOutput.Mode->Info->PixelInformation), &mPixelBitMask, sizeof (EFI_PIXEL_BITMASK));
FbGopPrivate->GraphicsOutput.Mode->Info->PixelsPerScanLine = (UINT32)(BytesPerScanLine * 8 / BitsPerPixel);
FbGopPrivate->GraphicsOutput.Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
FbGopPrivate->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) CurrentModeData->LinearFrameBuffer;
FbGopPrivate->GraphicsOutput.Mode->FrameBufferSize = CurrentModeData->FrameBufferSize;
//
// Find the best mode to initialize
//
Done:
//
// If there was an error, then free the mode structure
//
if (EFI_ERROR (Status)) {
if (VbeFrameBuffer != NULL) {
FreePool (VbeFrameBuffer);
}
if (ModeBuffer != NULL) {
FreePool (ModeBuffer);
}
}
return Status;
}
//
// Graphics Output Protocol Member Functions for VESA BIOS Extensions
//
/**
Graphics Output protocol interface to get video mode.
@param This Protocol instance pointer.
@param ModeNumber The mode number to return information on.
@param SizeOfInfo A pointer to the size, in bytes, of the Info
buffer.
@param Info Caller allocated buffer that returns information
about ModeNumber.
@retval EFI_SUCCESS Mode information returned.
@retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the
video mode.
@retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
@retval EFI_INVALID_PARAMETER One of the input args was NULL.
**/
EFI_STATUS
EFIAPI
FbGopGraphicsOutputQueryMode (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
IN UINT32 ModeNumber,
OUT UINTN *SizeOfInfo,
OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
)
{
FB_VIDEO_DEV *FbGopPrivate;
FB_VIDEO_MODE_DATA *ModeData;
FbGopPrivate = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
return EFI_INVALID_PARAMETER;
}
*Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
);
if (NULL == *Info) {
return EFI_OUT_OF_RESOURCES;
}
*SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
ModeData = &FbGopPrivate->ModeData[ModeNumber];
(*Info)->Version = 0;
(*Info)->HorizontalResolution = ModeData->HorizontalResolution;
(*Info)->VerticalResolution = ModeData->VerticalResolution;
(*Info)->PixelFormat = ModeData->PixelFormat;
CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(ModeData->PixelBitMask));
(*Info)->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
return EFI_SUCCESS;
}
/**
Graphics Output protocol interface to set video mode.
@param This Protocol instance pointer.
@param ModeNumber The mode number to be set.
@retval EFI_SUCCESS Graphics mode was changed.
@retval EFI_DEVICE_ERROR The device had an error and could not complete the
request.
@retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
**/
EFI_STATUS
EFIAPI
FbGopGraphicsOutputSetMode (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
IN UINT32 ModeNumber
)
{
FB_VIDEO_DEV *FbGopPrivate;
FB_VIDEO_MODE_DATA *ModeData;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
FbGopPrivate = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
ModeData = &FbGopPrivate->ModeData[ModeNumber];
if (ModeNumber >= This->Mode->MaxMode) {
return EFI_UNSUPPORTED;
}
if (ModeNumber == This->Mode->Mode) {
//
// Clear screen to black
//
ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
FbGopGraphicsOutputVbeBlt (
This,
&Background,
EfiBltVideoFill,
0,
0,
0,
0,
ModeData->HorizontalResolution,
ModeData->VerticalResolution,
0
);
return EFI_SUCCESS;
} else {
return EFI_UNSUPPORTED;
}
}
/**
Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
@param PciIo The pointer of EFI_PCI_IO_PROTOCOL
@param VbeBuffer The data to transfer to screen
@param MemAddress Physical frame buffer base address
@param DestinationX The X coordinate of the destination for BltOperation
@param DestinationY The Y coordinate of the destination for BltOperation
@param TotalBytes The total bytes of copy
@param VbePixelWidth Bytes per pixel
@param BytesPerScanLine Bytes per scan line
**/
VOID
CopyVideoBuffer (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 *VbeBuffer,
IN VOID *MemAddress,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN TotalBytes,
IN UINT32 VbePixelWidth,
IN UINTN BytesPerScanLine
)
{
UINTN FrameBufferAddr;
UINTN CopyBlockNum;
UINTN RemainingBytes;
UINTN UnalignedBytes;
EFI_STATUS Status;
FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;
//
// If TotalBytes is less than 4 bytes, only start byte copy.
//
if (TotalBytes < 4) {
Status = PciIo->Mem.Write (
PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
(UINT64) FrameBufferAddr,
TotalBytes,
VbeBuffer
);
ASSERT_EFI_ERROR (Status);
return;
}
//
// If VbeBuffer is not 4-byte aligned, start byte copy.
//
UnalignedBytes = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;
if (UnalignedBytes != 0) {
Status = PciIo->Mem.Write (
PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
(UINT64) FrameBufferAddr,
UnalignedBytes,
VbeBuffer
);
ASSERT_EFI_ERROR (Status);
FrameBufferAddr += UnalignedBytes;
VbeBuffer += UnalignedBytes;
}
//
// Calculate 4-byte block count and remaining bytes.
//
CopyBlockNum = (TotalBytes - UnalignedBytes) >> 2;
RemainingBytes = (TotalBytes - UnalignedBytes) & 3;
//
// Copy 4-byte block and remaining bytes to physical frame buffer.
//
if (CopyBlockNum != 0) {
Status = PciIo->Mem.Write (
PciIo,
EfiPciIoWidthUint32,
EFI_PCI_IO_PASS_THROUGH_BAR,
(UINT64) FrameBufferAddr,
CopyBlockNum,
VbeBuffer
);
ASSERT_EFI_ERROR (Status);
}
if (RemainingBytes != 0) {
FrameBufferAddr += (CopyBlockNum << 2);
VbeBuffer += (CopyBlockNum << 2);
Status = PciIo->Mem.Write (
PciIo,
EfiPciIoWidthUint8,
EFI_PCI_IO_PASS_THROUGH_BAR,
(UINT64) FrameBufferAddr,
RemainingBytes,
VbeBuffer
);
ASSERT_EFI_ERROR (Status);
}
}
/**
Worker function to block transfer for VBE device.
@param FbGopPrivate Instance of FB_VIDEO_DEV
@param BltBuffer The data to transfer to screen
@param BltOperation The operation to perform
@param SourceX The X coordinate of the source for BltOperation
@param SourceY The Y coordinate of the source for BltOperation
@param DestinationX The X coordinate of the destination for
BltOperation
@param DestinationY The Y coordinate of the destination for
BltOperation
@param Width The width of a rectangle in the blt rectangle in
pixels
@param Height The height of a rectangle in the blt rectangle in
pixels
@param Delta Not used for EfiBltVideoFill and
EfiBltVideoToVideo operation. If a Delta of 0 is
used, the entire BltBuffer will be operated on. If
a subrectangle of the BltBuffer is used, then
Delta represents the number of bytes in a row of
the BltBuffer.
@param Mode Mode data.
@retval EFI_INVALID_PARAMETER Invalid parameter passed in
@retval EFI_SUCCESS Blt operation success
**/
EFI_STATUS
FbGopVbeBltWorker (
IN FB_VIDEO_DEV *FbGopPrivate,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height,
IN UINTN Delta,
IN FB_VIDEO_MODE_DATA *Mode
)
{
EFI_PCI_IO_PROTOCOL *PciIo;
EFI_TPL OriginalTPL;
UINTN DstY;
UINTN SrcY;
UINTN DstX;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
VOID *MemAddress;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer;
UINTN BytesPerScanLine;
UINTN Index;
UINT8 *VbeBuffer;
UINT8 *VbeBuffer1;
UINT8 *BltUint8;
UINT32 VbePixelWidth;
UINT32 Pixel;
UINTN TotalBytes;
PciIo = FbGopPrivate->PciIo;
VbeFrameBuffer = FbGopPrivate->VbeFrameBuffer;
MemAddress = Mode->LinearFrameBuffer;
BytesPerScanLine = Mode->BytesPerScanLine;
VbePixelWidth = Mode->BitsPerPixel / 8;
BltUint8 = (UINT8 *) BltBuffer;
TotalBytes = Width * VbePixelWidth;
if (((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
return EFI_INVALID_PARAMETER;
}
if (Width == 0 || Height == 0) {
return EFI_INVALID_PARAMETER;
}
//
// We need to fill the Virtual Screen buffer with the blt data.
// The virtual screen is upside down, as the first row is the bottom row of
// the image.
//
if (BltOperation == EfiBltVideoToBltBuffer) {
//
// Video to BltBuffer: Source is Video, destination is BltBuffer
//
if (SourceY + Height > Mode->VerticalResolution) {
return EFI_INVALID_PARAMETER;
}
if (SourceX + Width > Mode->HorizontalResolution) {
return EFI_INVALID_PARAMETER;
}
} else {
//
// BltBuffer to Video: Source is BltBuffer, destination is Video
//
if (DestinationY + Height > Mode->VerticalResolution) {
return EFI_INVALID_PARAMETER;
}
if (DestinationX + Width > Mode->HorizontalResolution) {
return EFI_INVALID_PARAMETER;
}
}
//
// If Delta is zero, then the entire BltBuffer is being used, so Delta
// is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
// the number of bytes in each row can be computed.
//
if (Delta == 0) {
Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
}
//
// We have to raise to TPL Notify, so we make an atomic write the frame buffer.
// We would not want a timer based event (Cursor, ...) to come in while we are
// doing this operation.
//
OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
switch (BltOperation) {
case EfiBltVideoToBltBuffer:
for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
//
// Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
//
VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));
for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
Pixel = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24;
Blt->Red = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);
Blt->Blue = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);
Blt->Green = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);
Blt->Reserved = 0;
Blt++;
VbeBuffer += VbePixelWidth;
}
}
break;
case EfiBltVideoToVideo:
for (Index = 0; Index < Height; Index++) {
if (DestinationY <= SourceY) {
SrcY = SourceY + Index;
DstY = DestinationY + Index;
} else {
SrcY = SourceY + Height - Index - 1;
DstY = DestinationY + Height - Index - 1;
}
VbeBuffer = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);
VbeBuffer1 = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);
gBS->CopyMem (
VbeBuffer,
VbeBuffer1,
TotalBytes
);
//
// Update physical frame buffer.
//
CopyVideoBuffer (
PciIo,
VbeBuffer,
MemAddress,
DestinationX,
DstY,
TotalBytes,
VbePixelWidth,
BytesPerScanLine
);
}
break;
case EfiBltVideoFill:
VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8;
//
// Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
//
Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
(
(Blt->Green & Mode->Green.Mask) <<
Mode->Green.Position
) |
((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
for (Index = 0; Index < Width; Index++) {
gBS->CopyMem (
VbeBuffer,
&Pixel,
VbePixelWidth
);
VbeBuffer += VbePixelWidth;
}
VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {
gBS->CopyMem (
(VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),
VbeBuffer,
TotalBytes
);
}
for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
//
// Update physical frame buffer.
//
CopyVideoBuffer (
PciIo,
VbeBuffer,
MemAddress,
DestinationX,
DstY,
TotalBytes,
VbePixelWidth,
BytesPerScanLine
);
}
break;
case EfiBltBufferToVideo:
for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
//
// Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
//
Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |
((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
gBS->CopyMem (
VbeBuffer,
&Pixel,
VbePixelWidth
);
Blt++;
VbeBuffer += VbePixelWidth;
}
VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
//
// Update physical frame buffer.
//
CopyVideoBuffer (
PciIo,
VbeBuffer,
MemAddress,
DestinationX,
DstY,
TotalBytes,
VbePixelWidth,
BytesPerScanLine
);
}
break;
default: ;
}
gBS->RestoreTPL (OriginalTPL);
return EFI_SUCCESS;
}
/**
Graphics Output protocol instance to block transfer for VBE device.
@param This Pointer to Graphics Output protocol instance
@param BltBuffer The data to transfer to screen
@param BltOperation The operation to perform
@param SourceX The X coordinate of the source for BltOperation
@param SourceY The Y coordinate of the source for BltOperation
@param DestinationX The X coordinate of the destination for
BltOperation
@param DestinationY The Y coordinate of the destination for
BltOperation
@param Width The width of a rectangle in the blt rectangle in
pixels
@param Height The height of a rectangle in the blt rectangle in
pixels
@param Delta Not used for EfiBltVideoFill and
EfiBltVideoToVideo operation. If a Delta of 0 is
used, the entire BltBuffer will be operated on. If
a subrectangle of the BltBuffer is used, then
Delta represents the number of bytes in a row of
the BltBuffer.
@retval EFI_INVALID_PARAMETER Invalid parameter passed in
@retval EFI_SUCCESS Blt operation success
**/
EFI_STATUS
EFIAPI
FbGopGraphicsOutputVbeBlt (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height,
IN UINTN Delta
)
{
FB_VIDEO_DEV *FbGopPrivate;
FB_VIDEO_MODE_DATA *Mode;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
FbGopPrivate = FB_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
Mode = &FbGopPrivate->ModeData[This->Mode->Mode];
return FbGopVbeBltWorker (
FbGopPrivate,
BltBuffer,
BltOperation,
SourceX,
SourceY,
DestinationX,
DestinationY,
Width,
Height,
Delta,
Mode
);
}
/**
The user Entry Point for module UefiFbGop. The user code starts with this function.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval other Some error occurs when executing this entry point.
**/
EFI_STATUS
EFIAPI
FbGopEntryPoint(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HOB_GUID_TYPE *GuidHob;
//
// Find the frame buffer information guid hob
//
GuidHob = GetFirstGuidHob (&gUefiFrameBufferInfoGuid);
if (GuidHob != NULL) {
mFrameBufferInfo = (FRAME_BUFFER_INFO *)GET_GUID_HOB_DATA (GuidHob);
//
// Install driver model protocol(s).
//
Status = EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gFbGopDriverBinding,
ImageHandle,
&gFbGopComponentName,
&gFbGopComponentName2
);
ASSERT_EFI_ERROR (Status);
} else {
DEBUG ((DEBUG_ERROR, "No FrameBuffer information from coreboot. NO GOP driver !!!\n"));
Status = EFI_ABORTED;
}
return Status;
}