2019-02-02 16:41:15 +07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2016-04-26 03:06:49 +07:00
|
|
|
/* -----------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Copyright 2011 Intel Corporation; author Matt Fleming
|
|
|
|
*
|
|
|
|
* ----------------------------------------------------------------------- */
|
|
|
|
|
2020-03-20 09:00:22 +07:00
|
|
|
#include <linux/bitops.h>
|
2020-03-20 09:00:26 +07:00
|
|
|
#include <linux/ctype.h>
|
2016-04-26 03:06:49 +07:00
|
|
|
#include <linux/efi.h>
|
|
|
|
#include <linux/screen_info.h>
|
2020-03-20 09:00:25 +07:00
|
|
|
#include <linux/string.h>
|
2016-04-26 03:06:49 +07:00
|
|
|
#include <asm/efi.h>
|
|
|
|
#include <asm/setup.h>
|
|
|
|
|
2019-12-24 22:10:15 +07:00
|
|
|
#include "efistub.h"
|
|
|
|
|
2020-03-20 09:00:25 +07:00
|
|
|
enum efi_cmdline_option {
|
|
|
|
EFI_CMDLINE_NONE,
|
|
|
|
EFI_CMDLINE_MODE_NUM,
|
2020-03-28 23:06:01 +07:00
|
|
|
EFI_CMDLINE_RES,
|
|
|
|
EFI_CMDLINE_AUTO
|
2020-03-20 09:00:25 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
enum efi_cmdline_option option;
|
2020-03-20 09:00:26 +07:00
|
|
|
union {
|
|
|
|
u32 mode;
|
|
|
|
struct {
|
|
|
|
u32 width, height;
|
2020-03-20 09:00:27 +07:00
|
|
|
int format;
|
|
|
|
u8 depth;
|
2020-03-20 09:00:26 +07:00
|
|
|
} res;
|
|
|
|
};
|
2020-04-16 22:12:27 +07:00
|
|
|
} cmdline = { .option = EFI_CMDLINE_NONE };
|
2020-03-20 09:00:25 +07:00
|
|
|
|
|
|
|
static bool parse_modenum(char *option, char **next)
|
|
|
|
{
|
|
|
|
u32 m;
|
|
|
|
|
|
|
|
if (!strstarts(option, "mode="))
|
|
|
|
return false;
|
|
|
|
option += strlen("mode=");
|
|
|
|
m = simple_strtoull(option, &option, 0);
|
|
|
|
if (*option && *option++ != ',')
|
|
|
|
return false;
|
|
|
|
cmdline.option = EFI_CMDLINE_MODE_NUM;
|
|
|
|
cmdline.mode = m;
|
|
|
|
|
|
|
|
*next = option;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-03-20 09:00:26 +07:00
|
|
|
static bool parse_res(char *option, char **next)
|
|
|
|
{
|
2020-03-20 09:00:27 +07:00
|
|
|
u32 w, h, d = 0;
|
|
|
|
int pf = -1;
|
2020-03-20 09:00:26 +07:00
|
|
|
|
|
|
|
if (!isdigit(*option))
|
|
|
|
return false;
|
|
|
|
w = simple_strtoull(option, &option, 10);
|
|
|
|
if (*option++ != 'x' || !isdigit(*option))
|
|
|
|
return false;
|
|
|
|
h = simple_strtoull(option, &option, 10);
|
2020-03-20 09:00:27 +07:00
|
|
|
if (*option == '-') {
|
|
|
|
option++;
|
|
|
|
if (strstarts(option, "rgb")) {
|
|
|
|
option += strlen("rgb");
|
|
|
|
pf = PIXEL_RGB_RESERVED_8BIT_PER_COLOR;
|
|
|
|
} else if (strstarts(option, "bgr")) {
|
|
|
|
option += strlen("bgr");
|
|
|
|
pf = PIXEL_BGR_RESERVED_8BIT_PER_COLOR;
|
|
|
|
} else if (isdigit(*option))
|
|
|
|
d = simple_strtoull(option, &option, 10);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
2020-03-20 09:00:26 +07:00
|
|
|
if (*option && *option++ != ',')
|
|
|
|
return false;
|
|
|
|
cmdline.option = EFI_CMDLINE_RES;
|
|
|
|
cmdline.res.width = w;
|
|
|
|
cmdline.res.height = h;
|
2020-03-20 09:00:27 +07:00
|
|
|
cmdline.res.format = pf;
|
|
|
|
cmdline.res.depth = d;
|
2020-03-20 09:00:26 +07:00
|
|
|
|
|
|
|
*next = option;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-03-28 23:06:01 +07:00
|
|
|
static bool parse_auto(char *option, char **next)
|
|
|
|
{
|
|
|
|
if (!strstarts(option, "auto"))
|
|
|
|
return false;
|
|
|
|
option += strlen("auto");
|
|
|
|
if (*option && *option++ != ',')
|
|
|
|
return false;
|
|
|
|
cmdline.option = EFI_CMDLINE_AUTO;
|
|
|
|
|
|
|
|
*next = option;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-03-20 09:00:25 +07:00
|
|
|
void efi_parse_option_graphics(char *option)
|
|
|
|
{
|
|
|
|
while (*option) {
|
|
|
|
if (parse_modenum(option, &option))
|
|
|
|
continue;
|
2020-03-20 09:00:26 +07:00
|
|
|
if (parse_res(option, &option))
|
|
|
|
continue;
|
2020-03-28 23:06:01 +07:00
|
|
|
if (parse_auto(option, &option))
|
|
|
|
continue;
|
2020-03-20 09:00:25 +07:00
|
|
|
|
|
|
|
while (*option && *option++ != ',')
|
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static u32 choose_mode_modenum(efi_graphics_output_protocol_t *gop)
|
|
|
|
{
|
|
|
|
efi_status_t status;
|
|
|
|
|
|
|
|
efi_graphics_output_protocol_mode_t *mode;
|
|
|
|
efi_graphics_output_mode_info_t *info;
|
|
|
|
unsigned long info_size;
|
|
|
|
|
|
|
|
u32 max_mode, cur_mode;
|
|
|
|
int pf;
|
|
|
|
|
|
|
|
mode = efi_table_attr(gop, mode);
|
|
|
|
|
|
|
|
cur_mode = efi_table_attr(mode, mode);
|
|
|
|
if (cmdline.mode == cur_mode)
|
|
|
|
return cur_mode;
|
|
|
|
|
|
|
|
max_mode = efi_table_attr(mode, max_mode);
|
|
|
|
if (cmdline.mode >= max_mode) {
|
2020-05-01 01:28:37 +07:00
|
|
|
efi_err("Requested mode is invalid\n");
|
2020-03-20 09:00:25 +07:00
|
|
|
return cur_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = efi_call_proto(gop, query_mode, cmdline.mode,
|
|
|
|
&info_size, &info);
|
|
|
|
if (status != EFI_SUCCESS) {
|
2020-05-01 01:28:37 +07:00
|
|
|
efi_err("Couldn't get mode information\n");
|
2020-03-20 09:00:25 +07:00
|
|
|
return cur_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
pf = info->pixel_format;
|
|
|
|
|
|
|
|
efi_bs_call(free_pool, info);
|
|
|
|
|
|
|
|
if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX) {
|
2020-05-01 01:28:37 +07:00
|
|
|
efi_err("Invalid PixelFormat\n");
|
2020-03-20 09:00:25 +07:00
|
|
|
return cur_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cmdline.mode;
|
|
|
|
}
|
|
|
|
|
2020-03-20 09:00:27 +07:00
|
|
|
static u8 pixel_bpp(int pixel_format, efi_pixel_bitmask_t pixel_info)
|
|
|
|
{
|
|
|
|
if (pixel_format == PIXEL_BIT_MASK) {
|
|
|
|
u32 mask = pixel_info.red_mask | pixel_info.green_mask |
|
|
|
|
pixel_info.blue_mask | pixel_info.reserved_mask;
|
|
|
|
if (!mask)
|
|
|
|
return 0;
|
|
|
|
return __fls(mask) - __ffs(mask) + 1;
|
|
|
|
} else
|
|
|
|
return 32;
|
|
|
|
}
|
|
|
|
|
2020-03-20 09:00:26 +07:00
|
|
|
static u32 choose_mode_res(efi_graphics_output_protocol_t *gop)
|
|
|
|
{
|
|
|
|
efi_status_t status;
|
|
|
|
|
|
|
|
efi_graphics_output_protocol_mode_t *mode;
|
|
|
|
efi_graphics_output_mode_info_t *info;
|
|
|
|
unsigned long info_size;
|
|
|
|
|
|
|
|
u32 max_mode, cur_mode;
|
|
|
|
int pf;
|
2020-03-20 09:00:27 +07:00
|
|
|
efi_pixel_bitmask_t pi;
|
2020-03-20 09:00:26 +07:00
|
|
|
u32 m, w, h;
|
|
|
|
|
|
|
|
mode = efi_table_attr(gop, mode);
|
|
|
|
|
|
|
|
cur_mode = efi_table_attr(mode, mode);
|
|
|
|
info = efi_table_attr(mode, info);
|
2020-03-20 09:00:27 +07:00
|
|
|
pf = info->pixel_format;
|
|
|
|
pi = info->pixel_information;
|
|
|
|
w = info->horizontal_resolution;
|
|
|
|
h = info->vertical_resolution;
|
2020-03-20 09:00:26 +07:00
|
|
|
|
2020-03-20 09:00:27 +07:00
|
|
|
if (w == cmdline.res.width && h == cmdline.res.height &&
|
|
|
|
(cmdline.res.format < 0 || cmdline.res.format == pf) &&
|
|
|
|
(!cmdline.res.depth || cmdline.res.depth == pixel_bpp(pf, pi)))
|
2020-03-20 09:00:26 +07:00
|
|
|
return cur_mode;
|
|
|
|
|
|
|
|
max_mode = efi_table_attr(mode, max_mode);
|
|
|
|
|
|
|
|
for (m = 0; m < max_mode; m++) {
|
|
|
|
if (m == cur_mode)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
status = efi_call_proto(gop, query_mode, m,
|
|
|
|
&info_size, &info);
|
|
|
|
if (status != EFI_SUCCESS)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pf = info->pixel_format;
|
2020-03-20 09:00:27 +07:00
|
|
|
pi = info->pixel_information;
|
2020-03-20 09:00:26 +07:00
|
|
|
w = info->horizontal_resolution;
|
|
|
|
h = info->vertical_resolution;
|
|
|
|
|
|
|
|
efi_bs_call(free_pool, info);
|
|
|
|
|
|
|
|
if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX)
|
|
|
|
continue;
|
2020-03-20 09:00:27 +07:00
|
|
|
if (w == cmdline.res.width && h == cmdline.res.height &&
|
|
|
|
(cmdline.res.format < 0 || cmdline.res.format == pf) &&
|
|
|
|
(!cmdline.res.depth || cmdline.res.depth == pixel_bpp(pf, pi)))
|
2020-03-20 09:00:26 +07:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2020-05-01 01:28:37 +07:00
|
|
|
efi_err("Couldn't find requested mode\n");
|
2020-03-20 09:00:26 +07:00
|
|
|
|
|
|
|
return cur_mode;
|
|
|
|
}
|
|
|
|
|
2020-03-28 23:06:01 +07:00
|
|
|
static u32 choose_mode_auto(efi_graphics_output_protocol_t *gop)
|
|
|
|
{
|
|
|
|
efi_status_t status;
|
|
|
|
|
|
|
|
efi_graphics_output_protocol_mode_t *mode;
|
|
|
|
efi_graphics_output_mode_info_t *info;
|
|
|
|
unsigned long info_size;
|
|
|
|
|
|
|
|
u32 max_mode, cur_mode, best_mode, area;
|
|
|
|
u8 depth;
|
|
|
|
int pf;
|
|
|
|
efi_pixel_bitmask_t pi;
|
|
|
|
u32 m, w, h, a;
|
|
|
|
u8 d;
|
|
|
|
|
|
|
|
mode = efi_table_attr(gop, mode);
|
|
|
|
|
|
|
|
cur_mode = efi_table_attr(mode, mode);
|
|
|
|
max_mode = efi_table_attr(mode, max_mode);
|
|
|
|
|
|
|
|
info = efi_table_attr(mode, info);
|
|
|
|
|
|
|
|
pf = info->pixel_format;
|
|
|
|
pi = info->pixel_information;
|
|
|
|
w = info->horizontal_resolution;
|
|
|
|
h = info->vertical_resolution;
|
|
|
|
|
|
|
|
best_mode = cur_mode;
|
|
|
|
area = w * h;
|
|
|
|
depth = pixel_bpp(pf, pi);
|
|
|
|
|
|
|
|
for (m = 0; m < max_mode; m++) {
|
|
|
|
if (m == cur_mode)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
status = efi_call_proto(gop, query_mode, m,
|
|
|
|
&info_size, &info);
|
|
|
|
if (status != EFI_SUCCESS)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pf = info->pixel_format;
|
|
|
|
pi = info->pixel_information;
|
|
|
|
w = info->horizontal_resolution;
|
|
|
|
h = info->vertical_resolution;
|
|
|
|
|
|
|
|
efi_bs_call(free_pool, info);
|
|
|
|
|
|
|
|
if (pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX)
|
|
|
|
continue;
|
|
|
|
a = w * h;
|
|
|
|
if (a < area)
|
|
|
|
continue;
|
|
|
|
d = pixel_bpp(pf, pi);
|
|
|
|
if (a > area || d > depth) {
|
|
|
|
best_mode = m;
|
|
|
|
area = a;
|
|
|
|
depth = d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return best_mode;
|
|
|
|
}
|
|
|
|
|
2020-03-20 09:00:25 +07:00
|
|
|
static void set_mode(efi_graphics_output_protocol_t *gop)
|
|
|
|
{
|
|
|
|
efi_graphics_output_protocol_mode_t *mode;
|
|
|
|
u32 cur_mode, new_mode;
|
|
|
|
|
|
|
|
switch (cmdline.option) {
|
|
|
|
case EFI_CMDLINE_MODE_NUM:
|
|
|
|
new_mode = choose_mode_modenum(gop);
|
|
|
|
break;
|
2020-03-20 09:00:26 +07:00
|
|
|
case EFI_CMDLINE_RES:
|
|
|
|
new_mode = choose_mode_res(gop);
|
|
|
|
break;
|
2020-03-28 23:06:01 +07:00
|
|
|
case EFI_CMDLINE_AUTO:
|
|
|
|
new_mode = choose_mode_auto(gop);
|
|
|
|
break;
|
2020-03-20 09:00:25 +07:00
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mode = efi_table_attr(gop, mode);
|
|
|
|
cur_mode = efi_table_attr(mode, mode);
|
|
|
|
|
|
|
|
if (new_mode == cur_mode)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (efi_call_proto(gop, set_mode, new_mode) != EFI_SUCCESS)
|
2020-05-01 01:28:37 +07:00
|
|
|
efi_err("Failed to set requested mode\n");
|
2020-03-20 09:00:25 +07:00
|
|
|
}
|
|
|
|
|
2020-03-20 09:00:22 +07:00
|
|
|
static void find_bits(u32 mask, u8 *pos, u8 *size)
|
2016-04-26 03:06:49 +07:00
|
|
|
{
|
2020-03-20 09:00:22 +07:00
|
|
|
if (!mask) {
|
|
|
|
*pos = *size = 0;
|
|
|
|
return;
|
2016-04-26 03:06:49 +07:00
|
|
|
}
|
|
|
|
|
2020-03-20 09:00:22 +07:00
|
|
|
/* UEFI spec guarantees that the set bits are contiguous */
|
|
|
|
*pos = __ffs(mask);
|
|
|
|
*size = __fls(mask) - *pos + 1;
|
2016-04-26 03:06:49 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,
|
2019-12-24 22:10:03 +07:00
|
|
|
efi_pixel_bitmask_t pixel_info, int pixel_format)
|
2016-04-26 03:06:49 +07:00
|
|
|
{
|
2020-03-20 09:00:23 +07:00
|
|
|
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);
|
2016-04-26 03:06:49 +07:00
|
|
|
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 {
|
2020-03-20 09:00:23 +07:00
|
|
|
if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
|
|
|
|
si->red_pos = 0;
|
|
|
|
si->blue_pos = 16;
|
|
|
|
} else /* PIXEL_BGR_RESERVED_8BIT_PER_COLOR */ {
|
|
|
|
si->blue_pos = 0;
|
|
|
|
si->red_pos = 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
si->green_pos = 8;
|
|
|
|
si->rsvd_pos = 24;
|
|
|
|
si->red_size = si->green_size =
|
|
|
|
si->blue_size = si->rsvd_size = 8;
|
|
|
|
|
|
|
|
si->lfb_depth = 32;
|
|
|
|
si->lfb_linelength = pixels_per_scan_line * 4;
|
2016-04-26 03:06:49 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-20 09:00:18 +07:00
|
|
|
static efi_graphics_output_protocol_t *
|
|
|
|
find_gop(efi_guid_t *proto, unsigned long size, void **handles)
|
2016-04-26 03:06:49 +07:00
|
|
|
{
|
2020-03-20 09:00:20 +07:00
|
|
|
efi_graphics_output_protocol_t *first_gop;
|
2019-12-24 22:10:07 +07:00
|
|
|
efi_handle_t h;
|
2016-04-26 03:06:49 +07:00
|
|
|
int i;
|
|
|
|
|
|
|
|
first_gop = NULL;
|
|
|
|
|
2019-12-24 22:10:07 +07:00
|
|
|
for_each_efi_handle(h, handles, size, i) {
|
2020-03-20 09:00:20 +07:00
|
|
|
efi_status_t status;
|
|
|
|
|
|
|
|
efi_graphics_output_protocol_t *gop;
|
|
|
|
efi_graphics_output_protocol_mode_t *mode;
|
|
|
|
efi_graphics_output_mode_info_t *info;
|
|
|
|
|
2016-04-26 03:06:49 +07:00
|
|
|
efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
|
|
|
|
void *dummy = NULL;
|
|
|
|
|
efi/libstub: Rename efi_call_early/_runtime macros to be more intuitive
The macros efi_call_early and efi_call_runtime are used to call EFI
boot services and runtime services, respectively. However, the naming
is confusing, given that the early vs runtime distinction may suggest
that these are used for calling the same set of services either early
or late (== at runtime), while in reality, the sets of services they
can be used with are completely disjoint, and efi_call_runtime is also
only usable in 'early' code.
So do a global sweep to replace all occurrences with efi_bs_call or
efi_rt_call, respectively, where BS and RT match the idiom used by
the UEFI spec to refer to boot time or runtime services.
While at it, use 'func' as the macro parameter name for the function
pointers, which is less likely to collide and cause weird build errors.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Cc: Arvind Sankar <nivedita@alum.mit.edu>
Cc: Borislav Petkov <bp@alien8.de>
Cc: James Morse <james.morse@arm.com>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: https://lkml.kernel.org/r/20191224151025.32482-24-ardb@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-12-24 22:10:23 +07:00
|
|
|
status = efi_bs_call(handle_protocol, h, proto, (void **)&gop);
|
2016-04-26 03:06:49 +07:00
|
|
|
if (status != EFI_SUCCESS)
|
|
|
|
continue;
|
|
|
|
|
2020-03-20 09:00:16 +07:00
|
|
|
mode = efi_table_attr(gop, mode);
|
|
|
|
info = efi_table_attr(mode, info);
|
2020-03-20 09:00:23 +07:00
|
|
|
if (info->pixel_format == PIXEL_BLT_ONLY ||
|
|
|
|
info->pixel_format >= PIXEL_FORMAT_MAX)
|
2020-03-20 09:00:16 +07:00
|
|
|
continue;
|
|
|
|
|
2020-03-20 09:00:19 +07:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* Once we've found a GOP supporting ConOut,
|
|
|
|
* don't bother looking any further.
|
|
|
|
*/
|
efi/libstub: Rename efi_call_early/_runtime macros to be more intuitive
The macros efi_call_early and efi_call_runtime are used to call EFI
boot services and runtime services, respectively. However, the naming
is confusing, given that the early vs runtime distinction may suggest
that these are used for calling the same set of services either early
or late (== at runtime), while in reality, the sets of services they
can be used with are completely disjoint, and efi_call_runtime is also
only usable in 'early' code.
So do a global sweep to replace all occurrences with efi_bs_call or
efi_rt_call, respectively, where BS and RT match the idiom used by
the UEFI spec to refer to boot time or runtime services.
While at it, use 'func' as the macro parameter name for the function
pointers, which is less likely to collide and cause weird build errors.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Cc: Arvind Sankar <nivedita@alum.mit.edu>
Cc: Borislav Petkov <bp@alien8.de>
Cc: James Morse <james.morse@arm.com>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: https://lkml.kernel.org/r/20191224151025.32482-24-ardb@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-12-24 22:10:23 +07:00
|
|
|
status = efi_bs_call(handle_protocol, h, &conout_proto, &dummy);
|
2016-04-26 03:06:49 +07:00
|
|
|
if (status == EFI_SUCCESS)
|
2020-03-20 09:00:19 +07:00
|
|
|
return gop;
|
|
|
|
|
|
|
|
if (!first_gop)
|
2019-12-24 22:10:04 +07:00
|
|
|
first_gop = gop;
|
2016-04-26 03:06:49 +07:00
|
|
|
}
|
|
|
|
|
2020-03-20 09:00:18 +07:00
|
|
|
return first_gop;
|
|
|
|
}
|
|
|
|
|
|
|
|
static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
|
|
|
|
unsigned long size, void **handles)
|
|
|
|
{
|
|
|
|
efi_graphics_output_protocol_t *gop;
|
|
|
|
efi_graphics_output_protocol_mode_t *mode;
|
2020-03-20 09:00:20 +07:00
|
|
|
efi_graphics_output_mode_info_t *info;
|
2020-03-20 09:00:18 +07:00
|
|
|
|
|
|
|
gop = find_gop(proto, size, handles);
|
|
|
|
|
2016-04-26 03:06:49 +07:00
|
|
|
/* Did we find any GOPs? */
|
2020-03-20 09:00:18 +07:00
|
|
|
if (!gop)
|
2019-12-06 23:55:38 +07:00
|
|
|
return EFI_NOT_FOUND;
|
2016-04-26 03:06:49 +07:00
|
|
|
|
2020-03-20 09:00:25 +07:00
|
|
|
/* Change mode if requested */
|
|
|
|
set_mode(gop);
|
|
|
|
|
2016-04-26 03:06:49 +07:00
|
|
|
/* EFI framebuffer */
|
2020-03-20 09:00:18 +07:00
|
|
|
mode = efi_table_attr(gop, mode);
|
2020-03-20 09:00:17 +07:00
|
|
|
info = efi_table_attr(mode, info);
|
|
|
|
|
2016-04-26 03:06:49 +07:00
|
|
|
si->orig_video_isVGA = VIDEO_TYPE_EFI;
|
|
|
|
|
2020-03-20 09:00:17 +07:00
|
|
|
si->lfb_width = info->horizontal_resolution;
|
|
|
|
si->lfb_height = info->vertical_resolution;
|
2016-04-26 03:06:49 +07:00
|
|
|
|
2020-05-01 01:28:34 +07:00
|
|
|
efi_set_u64_split(efi_table_attr(mode, frame_buffer_base),
|
|
|
|
&si->lfb_base, &si->ext_lfb_base);
|
2020-03-20 09:00:17 +07:00
|
|
|
if (si->ext_lfb_base)
|
2016-04-26 03:06:49 +07:00
|
|
|
si->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
|
|
|
|
|
|
|
|
si->pages = 1;
|
|
|
|
|
2020-03-20 09:00:17 +07:00
|
|
|
setup_pixel_info(si, info->pixels_per_scan_line,
|
|
|
|
info->pixel_information, info->pixel_format);
|
2016-04-26 03:06:49 +07:00
|
|
|
|
|
|
|
si->lfb_size = si->lfb_linelength * si->lfb_height;
|
|
|
|
|
|
|
|
si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
|
2019-12-06 23:55:38 +07:00
|
|
|
|
2019-12-06 23:55:39 +07:00
|
|
|
return EFI_SUCCESS;
|
2016-04-26 03:06:49 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if we have Graphics Output Protocol
|
|
|
|
*/
|
2019-12-24 22:10:19 +07:00
|
|
|
efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto,
|
2016-04-26 03:06:49 +07:00
|
|
|
unsigned long size)
|
|
|
|
{
|
|
|
|
efi_status_t status;
|
|
|
|
void **gop_handle = NULL;
|
|
|
|
|
efi/libstub: Rename efi_call_early/_runtime macros to be more intuitive
The macros efi_call_early and efi_call_runtime are used to call EFI
boot services and runtime services, respectively. However, the naming
is confusing, given that the early vs runtime distinction may suggest
that these are used for calling the same set of services either early
or late (== at runtime), while in reality, the sets of services they
can be used with are completely disjoint, and efi_call_runtime is also
only usable in 'early' code.
So do a global sweep to replace all occurrences with efi_bs_call or
efi_rt_call, respectively, where BS and RT match the idiom used by
the UEFI spec to refer to boot time or runtime services.
While at it, use 'func' as the macro parameter name for the function
pointers, which is less likely to collide and cause weird build errors.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Cc: Arvind Sankar <nivedita@alum.mit.edu>
Cc: Borislav Petkov <bp@alien8.de>
Cc: James Morse <james.morse@arm.com>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: https://lkml.kernel.org/r/20191224151025.32482-24-ardb@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-12-24 22:10:23 +07:00
|
|
|
status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
|
|
|
|
(void **)&gop_handle);
|
2016-04-26 03:06:49 +07:00
|
|
|
if (status != EFI_SUCCESS)
|
|
|
|
return status;
|
|
|
|
|
efi/libstub: Rename efi_call_early/_runtime macros to be more intuitive
The macros efi_call_early and efi_call_runtime are used to call EFI
boot services and runtime services, respectively. However, the naming
is confusing, given that the early vs runtime distinction may suggest
that these are used for calling the same set of services either early
or late (== at runtime), while in reality, the sets of services they
can be used with are completely disjoint, and efi_call_runtime is also
only usable in 'early' code.
So do a global sweep to replace all occurrences with efi_bs_call or
efi_rt_call, respectively, where BS and RT match the idiom used by
the UEFI spec to refer to boot time or runtime services.
While at it, use 'func' as the macro parameter name for the function
pointers, which is less likely to collide and cause weird build errors.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Cc: Arvind Sankar <nivedita@alum.mit.edu>
Cc: Borislav Petkov <bp@alien8.de>
Cc: James Morse <james.morse@arm.com>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: https://lkml.kernel.org/r/20191224151025.32482-24-ardb@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-12-24 22:10:23 +07:00
|
|
|
status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL, proto, NULL,
|
|
|
|
&size, gop_handle);
|
2016-04-26 03:06:49 +07:00
|
|
|
if (status != EFI_SUCCESS)
|
|
|
|
goto free_handle;
|
|
|
|
|
2019-12-24 22:10:19 +07:00
|
|
|
status = setup_gop(si, proto, size, gop_handle);
|
2016-04-26 03:06:49 +07:00
|
|
|
|
|
|
|
free_handle:
|
efi/libstub: Rename efi_call_early/_runtime macros to be more intuitive
The macros efi_call_early and efi_call_runtime are used to call EFI
boot services and runtime services, respectively. However, the naming
is confusing, given that the early vs runtime distinction may suggest
that these are used for calling the same set of services either early
or late (== at runtime), while in reality, the sets of services they
can be used with are completely disjoint, and efi_call_runtime is also
only usable in 'early' code.
So do a global sweep to replace all occurrences with efi_bs_call or
efi_rt_call, respectively, where BS and RT match the idiom used by
the UEFI spec to refer to boot time or runtime services.
While at it, use 'func' as the macro parameter name for the function
pointers, which is less likely to collide and cause weird build errors.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Cc: Arvind Sankar <nivedita@alum.mit.edu>
Cc: Borislav Petkov <bp@alien8.de>
Cc: James Morse <james.morse@arm.com>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: https://lkml.kernel.org/r/20191224151025.32482-24-ardb@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-12-24 22:10:23 +07:00
|
|
|
efi_bs_call(free_pool, gop_handle);
|
2016-04-26 03:06:49 +07:00
|
|
|
return status;
|
|
|
|
}
|