reactos/boot/environ/lib/io/display/efi/gop.c

280 lines
8.4 KiB
C

/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/display/efi/gop.c
* PURPOSE: Boot Library EFI GOP Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
/* FUNCTIONS *****************************************************************/
NTSTATUS
ConsoleEfiGopGetGraphicalFormat (
_In_ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *ModeInfo,
_Out_ PULONG PixelDepth
)
{
/* Convert the format to depth */
if (ModeInfo->PixelFormat == PixelBlueGreenRedReserved8BitPerColor)
{
*PixelDepth = 32;
return STATUS_SUCCESS;
}
if (ModeInfo->PixelFormat == PixelBitMask)
{
*PixelDepth = 24;
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
BOOLEAN
ConsoleEfiGopIsPixelFormatSupported (
_In_ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Mode
)
{
BOOLEAN Supported;
EFI_PIXEL_BITMASK PixelMask;
Supported = FALSE;
/* Check if it's simple BGR8 */
if (Mode->PixelFormat == PixelBlueGreenRedReserved8BitPerColor)
{
Supported = TRUE;
}
else
{
/* Otherwise, we can check if it's a masked format */
if (Mode->PixelFormat == PixelBitMask)
{
/* Check if the masked format is BGR8 */
PixelMask.BlueMask = 0xFF;
PixelMask.GreenMask = 0xFF00;
PixelMask.RedMask = 0xFF0000;
PixelMask.ReservedMask = 0;
if (RtlEqualMemory(&Mode->PixelInformation,
&PixelMask,
sizeof(PixelMask)))
{
Supported = TRUE;
}
}
}
/* Return if the format was supported */
return Supported;
}
NTSTATUS
ConsoleEfiGopFindModeFromAllowed (
_In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopProtocol,
_In_ PBL_DISPLAY_MODE SupportedModes,
_In_ ULONG MaximumIndex,
_Out_ PULONG SupportedMode
)
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
ConsoleEfiGopEnable (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
PVOID FrameBuffer;
UINTN CurrentMode, Dummy;
ULONG Mode, PixelDepth;
UINTN FrameBufferSize;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ModeInformation;
EFI_GRAPHICS_OUTPUT_PROTOCOL* Protocol;
NTSTATUS Status;
PHYSICAL_ADDRESS FrameBufferPhysical;
/* Capture the current mode and protocol */
Mode = GraphicsConsole->Mode;
Protocol = GraphicsConsole->Protocol;
/* Get the current mode and its information */
Status = EfiGopGetCurrentMode(Protocol, &CurrentMode, &ModeInformation);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Check if we're not in the mode we should be */
if (CurrentMode != Mode)
{
/* Switch modes */
Status = EfiGopSetMode(Protocol, Mode);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Reset the OEM bitmap and get the new more information */
BlDisplayInvalidateOemBitmap();
EfiGopGetCurrentMode(Protocol, &Dummy, &ModeInformation);
}
/* Get the pixel depth for this mode */
Status = ConsoleEfiGopGetGraphicalFormat(&ModeInformation, &PixelDepth);
if (NT_SUCCESS(Status))
{
/* Get the framebuffer for this mode */
EfiGopGetFrameBuffer(Protocol, &FrameBufferPhysical, &FrameBufferSize);
/* Map the framebuffer, try as writeback first */
FrameBuffer = NULL;
Status = BlMmMapPhysicalAddressEx(&FrameBuffer,
BlMemoryWriteBack,
FrameBufferSize,
FrameBufferPhysical);
if (!NT_SUCCESS(Status))
{
/* That didn't work, so try uncached next */
Status = BlMmMapPhysicalAddressEx(&FrameBuffer,
BlMemoryUncached,
FrameBufferSize,
FrameBufferPhysical);
}
}
/* Check if getting all the required information worked out */
if (NT_SUCCESS(Status))
{
/* Capture the resolution, depth, and framebuffer information */
GraphicsConsole->DisplayMode.HRes = ModeInformation.HorizontalResolution;
GraphicsConsole->DisplayMode.VRes = ModeInformation.VerticalResolution;
GraphicsConsole->DisplayMode.HRes2 = ModeInformation.PixelsPerScanLine;
GraphicsConsole->PixelDepth = PixelDepth;
GraphicsConsole->FrameBuffer = FrameBuffer;
GraphicsConsole->FrameBufferSize = FrameBufferSize;
GraphicsConsole->PixelsPerScanLine = ModeInformation.PixelsPerScanLine;
/* All good */
Status = STATUS_SUCCESS;
}
else if (CurrentMode != GraphicsConsole->Mode)
{
/* We failed somewhere, reset the mode and the OEM bitmap back */
EfiGopSetMode(Protocol, CurrentMode);
BlDisplayInvalidateOemBitmap();
}
/* Return back to caller */
return Status;
}
VOID
ConsoleEfiGopClose (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
ULONG OldMode;
/* Did we switch modes when we turned on the console? */
OldMode = GraphicsConsole->OldMode;
if (GraphicsConsole->Mode != OldMode)
{
/* Restore the old mode and reset the OEM bitmap in ACPI */
EfiGopSetMode(GraphicsConsole->Protocol, OldMode);
BlDisplayInvalidateOemBitmap();
}
/* Close the GOP protocol */
EfiCloseProtocol(GraphicsConsole->Handle,
&EfiGraphicsOutputProtocol);
}
NTSTATUS
ConsoleEfiGopOpen (
_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
)
{
NTSTATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GopProtocol;
ULONG Mode, PixelDepth;
UINTN CurrentMode;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ModeInformation;
BOOLEAN CurrentModeOk;
/* Open a handle to GOP */
Status = EfiOpenProtocol(GraphicsConsole->Handle,
&EfiGraphicsOutputProtocol,
(PVOID*)&GopProtocol);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"GOP OPEN failed: %lx\r\n", Status);
return STATUS_NOT_SUPPORTED;
}
/* Get the current mode */
Status = EfiGopGetCurrentMode(GopProtocol, &CurrentMode, &ModeInformation);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"GOP mode failed: %lx\r\n", Status);
goto Quickie;
}
Mode = CurrentMode;
/* Check if any custom BCD options were provided */
if (ConsoleGraphicalResolutionListFlags &
(BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG |
BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG))
{
/* We'll have to find a mode */
CurrentModeOk = FALSE;
}
else
{
/* Then we should be in the default mode, check if the pixel format is OK */
CurrentModeOk = ConsoleEfiGopIsPixelFormatSupported(&ModeInformation);
}
/* Is the mode/format OK? */
if (!CurrentModeOk)
{
/* Nope -- we'll have to go find one */
Status = ConsoleEfiGopFindModeFromAllowed(GopProtocol,
ConsoleGraphicalResolutionList,
ConsoleGraphicalResolutionListSize,
&Mode);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
}
/* Store mode information */
GraphicsConsole->Protocol = GopProtocol;
GraphicsConsole->Mode = Mode;
GraphicsConsole->OldMode = CurrentMode;
/* Get format information */
Status = ConsoleEfiGopGetGraphicalFormat(&ModeInformation, &PixelDepth);
if (NT_SUCCESS(Status))
{
/* Store it */
GraphicsConsole->OldDisplayMode.HRes = ModeInformation.HorizontalResolution;
GraphicsConsole->OldDisplayMode.VRes = ModeInformation.VerticalResolution;
GraphicsConsole->OldDisplayMode.HRes2 = ModeInformation.PixelsPerScanLine;
GraphicsConsole->PixelDepth = PixelDepth;
return STATUS_SUCCESS;
}
Quickie:
/* We failed, close the protocol and return the failure code */
EfiPrintf(L"Get format failed: %lx\r\n", Status);
EfiCloseProtocol(GraphicsConsole->Handle, &EfiGraphicsOutputProtocol);
return Status;
}