blob: b81bc58a269c4c5ca6aad19012b5351b665713d5 [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <assert.h>
#include "base/algorithm.h"
#include "base/xalloc.h"
#include "drivers/framebuffer/framebuffer.h"
#include "drivers/framebuffer/uefi.h"
#include "uefi/edk/Protocol/GraphicsOutput.h"
#include "uefi/uefi.h"
static EFI_GUID uefi_graphics_output_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static int uefi_framebuffer_prepare(FrameBufferOps *me, FrameBuffer *buf)
{
if (!framebuffer_read_from_fwdb(buf))
return 0;
EFI_SYSTEM_TABLE *st = uefi_system_table_ptr();
assert(st);
EFI_BOOT_SERVICES *bs = st->BootServices;
UINTN buf_size = 0;
EFI_HANDLE dummy_handle;
EFI_STATUS status = bs->LocateHandle(
ByProtocol, &uefi_graphics_output_guid, NULL,
&buf_size, &dummy_handle);
if (status == EFI_NOT_FOUND) {
printf("No graphics output handles found.\n");
return 1;
}
if (status != EFI_BUFFER_TOO_SMALL) {
printf("Error retrieving graphics output protocol handles.\n");
return 1;
}
EFI_HANDLE *handles = xmalloc(buf_size);
status = bs->LocateHandle(
ByProtocol, &uefi_graphics_output_guid, NULL,
&buf_size, handles);
if (status != EFI_SUCCESS) {
printf("Failed to retrieve graphics output "
"protocol handles.\n");
free(handles);
return 1;
}
int handle_count = buf_size / sizeof(dummy_handle);
if (handle_count > 1) {
printf("Multiple graphics output devices found. Using the "
"first one.\n");
}
EFI_GRAPHICS_OUTPUT_PROTOCOL *gp;
status = bs->HandleProtocol(
handles[0], &uefi_graphics_output_guid, (void **)&gp);
if (status != EFI_SUCCESS) {
printf("Failed to extract graphics output protocol.\n");
free(handles);
return 1;
}
free(handles);
buf->header.version = FrameBufferCurrentVersion;
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *mode = gp->Mode;
buf->buffer = (void *)(uintptr_t)mode->FrameBufferBase;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info = mode->Info;
buf->resolution.x = info->HorizontalResolution;
buf->resolution.y = info->VerticalResolution;
EFI_PIXEL_BITMASK *bm = &info->PixelInformation;
switch (info->PixelFormat) {
case PixelRedGreenBlueReserved8BitPerColor:
buf->red.size = buf->green.size = buf->blue.size = 8;
buf->red.pos = 0;
buf->green.pos = 8;
buf->blue.pos = 16;
buf->bits_per_pixel = 32;
break;
case PixelBlueGreenRedReserved8BitPerColor:
buf->red.size = buf->green.size = buf->blue.size = 8;
buf->blue.pos = 0;
buf->green.pos = 8;
buf->red.pos = 16;
buf->bits_per_pixel = 32;
break;
case PixelBitMask:
buf->red.pos = CTZ(bm->RedMask);
buf->red.size = CTZ(~bm->RedMask >> buf->red.pos);
buf->green.pos = CTZ(bm->GreenMask);
buf->green.size = CTZ(~bm->GreenMask >> buf->green.pos);
buf->blue.pos = CTZ(bm->BlueMask);
buf->blue.size = CTZ(~bm->BlueMask >> buf->blue.pos);
case PixelBltOnly:
printf("Physical framebuffer not supported.\n");
return 1;
default:
printf("Unrecognized pixel format %d.\n", info->PixelFormat);
return 1;
}
buf->bytes_per_line =
((buf->bits_per_pixel + 7) / 8) * info->PixelsPerScanLine;
return framebuffer_write_to_fwdb(buf);
}
FrameBufferOps *new_uefi_framebuffer(void)
{
FrameBufferOps *fb = xzalloc(sizeof(*fb));
fb->prepare = &uefi_framebuffer_prepare;
return fb;
}