Skip to content

Commit

Permalink
efi/libstub: Move Graphics Output Protocol handling to generic code
Browse files Browse the repository at this point in the history
The Graphics Output Protocol code executes in the stub, so create a generic
version based on the x86 version in libstub so that we can move other archs
to it in subsequent patches. The new source file gop.c is added to the
libstub build for all architectures, but only wired up for x86.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Borislav Petkov <bp@alien8.de>
Cc: David Herrmann <dh.herrmann@gmail.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Jones <pjones@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will.deacon@arm.com>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/1461614832-17633-18-git-send-email-matt@codeblueprint.co.uk
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Ard Biesheuvel authored and Ingo Molnar committed Apr 28, 2016
1 parent 2c23b73 commit fc37206
Show file tree
Hide file tree
Showing 7 changed files with 441 additions and 400 deletions.
4 changes: 3 additions & 1 deletion arch/arm/include/asm/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ void efi_virtmap_unload(void);

/* arch specific definitions used by the stub code */

#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
#define __efi_call_early(f, ...) f(__VA_ARGS__)
#define efi_is_64bit() (false)

/*
* A reasonable upper bound for the uncompressed kernel size is 32 MBytes,
Expand Down
4 changes: 3 additions & 1 deletion arch/arm64/include/asm/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
#define EFI_FDT_ALIGN SZ_2M /* used by allocate_new_fdt_and_exit_boot() */
#define MAX_FDT_OFFSET SZ_512M

#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
#define __efi_call_early(f, ...) f(__VA_ARGS__)
#define efi_is_64bit() (true)

#define EFI_ALLOC_ALIGN SZ_64K

Expand Down
318 changes: 0 additions & 318 deletions arch/x86/boot/compressed/eboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,324 +571,6 @@ static void setup_efi_pci(struct boot_params *params)
efi_call_early(free_pool, pci_handle);
}

static void
setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
struct efi_pixel_bitmask pixel_info, int pixel_format)
{
if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
si->lfb_depth = 32;
si->lfb_linelength = pixels_per_scan_line * 4;
si->red_size = 8;
si->red_pos = 0;
si->green_size = 8;
si->green_pos = 8;
si->blue_size = 8;
si->blue_pos = 16;
si->rsvd_size = 8;
si->rsvd_pos = 24;
} else if (pixel_format == PIXEL_BGR_RESERVED_8BIT_PER_COLOR) {
si->lfb_depth = 32;
si->lfb_linelength = pixels_per_scan_line * 4;
si->red_size = 8;
si->red_pos = 16;
si->green_size = 8;
si->green_pos = 8;
si->blue_size = 8;
si->blue_pos = 0;
si->rsvd_size = 8;
si->rsvd_pos = 24;
} else if (pixel_format == PIXEL_BIT_MASK) {
find_bits(pixel_info.red_mask, &si->red_pos, &si->red_size);
find_bits(pixel_info.green_mask, &si->green_pos,
&si->green_size);
find_bits(pixel_info.blue_mask, &si->blue_pos, &si->blue_size);
find_bits(pixel_info.reserved_mask, &si->rsvd_pos,
&si->rsvd_size);
si->lfb_depth = si->red_size + si->green_size +
si->blue_size + si->rsvd_size;
si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8;
} else {
si->lfb_depth = 4;
si->lfb_linelength = si->lfb_width / 2;
si->red_size = 0;
si->red_pos = 0;
si->green_size = 0;
si->green_pos = 0;
si->blue_size = 0;
si->blue_pos = 0;
si->rsvd_size = 0;
si->rsvd_pos = 0;
}
}

static efi_status_t
__gop_query32(efi_system_table_t *sys_table_arg,
struct efi_graphics_output_protocol_32 *gop32,
struct efi_graphics_output_mode_info **info,
unsigned long *size, u64 *fb_base)
{
struct efi_graphics_output_protocol_mode_32 *mode;
efi_graphics_output_protocol_query_mode query_mode;
efi_status_t status;
unsigned long m;

m = gop32->mode;
mode = (struct efi_graphics_output_protocol_mode_32 *)m;
query_mode = (void *)(unsigned long)gop32->query_mode;

status = __efi_call_early(query_mode, (void *)gop32, mode->mode, size,
info);
if (status != EFI_SUCCESS)
return status;

*fb_base = mode->frame_buffer_base;
return status;
}

static efi_status_t
setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si,
efi_guid_t *proto, unsigned long size, void **gop_handle)
{
struct efi_graphics_output_protocol_32 *gop32, *first_gop;
unsigned long nr_gops;
u16 width, height;
u32 pixels_per_scan_line;
u32 ext_lfb_base;
u64 fb_base;
struct efi_pixel_bitmask pixel_info;
int pixel_format;
efi_status_t status = EFI_NOT_FOUND;
u32 *handles = (u32 *)(unsigned long)gop_handle;
int i;

first_gop = NULL;
gop32 = NULL;

nr_gops = size / sizeof(u32);
for (i = 0; i < nr_gops; i++) {
struct efi_graphics_output_mode_info *info = NULL;
efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
bool conout_found = false;
void *dummy = NULL;
efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
u64 current_fb_base;

status = efi_call_early(handle_protocol, h,
proto, (void **)&gop32);
if (status != EFI_SUCCESS)
continue;

status = efi_call_early(handle_protocol, h,
&conout_proto, &dummy);
if (status == EFI_SUCCESS)
conout_found = true;

status = __gop_query32(sys_table_arg, gop32, &info, &size,
&current_fb_base);
if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
/*
* Systems that use the UEFI Console Splitter may
* provide multiple GOP devices, not all of which are
* backed by real hardware. The workaround is to search
* for a GOP implementing the ConOut protocol, and if
* one isn't found, to just fall back to the first GOP.
*/
width = info->horizontal_resolution;
height = info->vertical_resolution;
pixel_format = info->pixel_format;
pixel_info = info->pixel_information;
pixels_per_scan_line = info->pixels_per_scan_line;
fb_base = current_fb_base;

/*
* Once we've found a GOP supporting ConOut,
* don't bother looking any further.
*/
first_gop = gop32;
if (conout_found)
break;
}
}

/* Did we find any GOPs? */
if (!first_gop)
goto out;

/* EFI framebuffer */
si->orig_video_isVGA = VIDEO_TYPE_EFI;

si->lfb_width = width;
si->lfb_height = height;
si->lfb_base = fb_base;

ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
if (ext_lfb_base) {
si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
si->ext_lfb_base = ext_lfb_base;
}

si->pages = 1;

setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);

si->lfb_size = si->lfb_linelength * si->lfb_height;

si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
out:
return status;
}

static efi_status_t
__gop_query64(efi_system_table_t *sys_table_arg,
struct efi_graphics_output_protocol_64 *gop64,
struct efi_graphics_output_mode_info **info,
unsigned long *size, u64 *fb_base)
{
struct efi_graphics_output_protocol_mode_64 *mode;
efi_graphics_output_protocol_query_mode query_mode;
efi_status_t status;
unsigned long m;

m = gop64->mode;
mode = (struct efi_graphics_output_protocol_mode_64 *)m;
query_mode = (void *)(unsigned long)gop64->query_mode;

status = __efi_call_early(query_mode, (void *)gop64, mode->mode, size,
info);
if (status != EFI_SUCCESS)
return status;

*fb_base = mode->frame_buffer_base;
return status;
}

static efi_status_t
setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si,
efi_guid_t *proto, unsigned long size, void **gop_handle)
{
struct efi_graphics_output_protocol_64 *gop64, *first_gop;
unsigned long nr_gops;
u16 width, height;
u32 pixels_per_scan_line;
u32 ext_lfb_base;
u64 fb_base;
struct efi_pixel_bitmask pixel_info;
int pixel_format;
efi_status_t status = EFI_NOT_FOUND;
u64 *handles = (u64 *)(unsigned long)gop_handle;
int i;

first_gop = NULL;
gop64 = NULL;

nr_gops = size / sizeof(u64);
for (i = 0; i < nr_gops; i++) {
struct efi_graphics_output_mode_info *info = NULL;
efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
bool conout_found = false;
void *dummy = NULL;
efi_handle_t h = (efi_handle_t)(unsigned long)handles[i];
u64 current_fb_base;

status = efi_call_early(handle_protocol, h,
proto, (void **)&gop64);
if (status != EFI_SUCCESS)
continue;

status = efi_call_early(handle_protocol, h,
&conout_proto, &dummy);
if (status == EFI_SUCCESS)
conout_found = true;

status = __gop_query64(sys_table_arg, gop64, &info, &size,
&current_fb_base);
if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
/*
* Systems that use the UEFI Console Splitter may
* provide multiple GOP devices, not all of which are
* backed by real hardware. The workaround is to search
* for a GOP implementing the ConOut protocol, and if
* one isn't found, to just fall back to the first GOP.
*/
width = info->horizontal_resolution;
height = info->vertical_resolution;
pixel_format = info->pixel_format;
pixel_info = info->pixel_information;
pixels_per_scan_line = info->pixels_per_scan_line;
fb_base = current_fb_base;

/*
* Once we've found a GOP supporting ConOut,
* don't bother looking any further.
*/
first_gop = gop64;
if (conout_found)
break;
}
}

/* Did we find any GOPs? */
if (!first_gop)
goto out;

/* EFI framebuffer */
si->orig_video_isVGA = VIDEO_TYPE_EFI;

si->lfb_width = width;
si->lfb_height = height;
si->lfb_base = fb_base;

ext_lfb_base = (u64)(unsigned long)fb_base >> 32;
if (ext_lfb_base) {
si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
si->ext_lfb_base = ext_lfb_base;
}

si->pages = 1;

setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format);

si->lfb_size = si->lfb_linelength * si->lfb_height;

si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
out:
return status;
}

/*
* See if we have Graphics Output Protocol
*/
efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg,
struct screen_info *si, efi_guid_t *proto,
unsigned long size)
{
efi_status_t status;
void **gop_handle = NULL;

status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
size, (void **)&gop_handle);
if (status != EFI_SUCCESS)
return status;

status = efi_call_early(locate_handle,
EFI_LOCATE_BY_PROTOCOL,
proto, NULL, &size, gop_handle);
if (status != EFI_SUCCESS)
goto free_handle;

if (efi_is_64bit()) {
status = setup_gop64(sys_table_arg, si, proto, size,
gop_handle);
} else {
status = setup_gop32(sys_table_arg, si, proto, size,
gop_handle);
}

free_handle:
efi_call_early(free_pool, gop_handle);
return status;
}

static efi_status_t
setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
{
Expand Down
Loading

0 comments on commit fc37206

Please sign in to comment.