Commit 14c574f3 authored by Arvind Sankar's avatar Arvind Sankar Committed by Ard Biesheuvel

efi/gop: Add an option to list out the available GOP modes

Add video=efifb:list option to list the modes that are available.
Signed-off-by: default avatarArvind Sankar <nivedita@alum.mit.edu>
Link: https://lore.kernel.org/r/20200518190716.751506-20-nivedita@alum.mit.eduSigned-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
parent 9b47c527
...@@ -63,4 +63,9 @@ auto ...@@ -63,4 +63,9 @@ auto
with the highest resolution, it will choose one with the highest color with the highest resolution, it will choose one with the highest color
depth. depth.
list
The EFI stub will list out all the display modes that are available. A
specific mode can then be chosen using one of the above options for the
next boot.
Edgar Hucek <gimli@dark-green.com> Edgar Hucek <gimli@dark-green.com>
...@@ -463,3 +463,38 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image, ...@@ -463,3 +463,38 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image,
return status; return status;
} }
efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key)
{
efi_event_t events[2], timer;
unsigned long index;
efi_simple_text_input_protocol_t *con_in;
efi_status_t status;
con_in = efi_table_attr(efi_system_table, con_in);
if (!con_in)
return EFI_UNSUPPORTED;
efi_set_event_at(events, 0, efi_table_attr(con_in, wait_for_key));
status = efi_bs_call(create_event, EFI_EVT_TIMER, 0, NULL, NULL, &timer);
if (status != EFI_SUCCESS)
return status;
status = efi_bs_call(set_timer, timer, EfiTimerRelative,
EFI_100NSEC_PER_USEC * usec);
if (status != EFI_SUCCESS)
return status;
efi_set_event_at(events, 1, timer);
status = efi_bs_call(wait_for_event, 2, events, &index);
if (status == EFI_SUCCESS) {
if (index == 0)
status = efi_call_proto(con_in, read_keystroke, key);
else
status = EFI_TIMEOUT;
}
efi_bs_call(close_event, timer);
return status;
}
...@@ -323,6 +323,8 @@ union efi_simple_text_input_protocol { ...@@ -323,6 +323,8 @@ union efi_simple_text_input_protocol {
} mixed_mode; } mixed_mode;
}; };
efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key);
union efi_simple_text_output_protocol { union efi_simple_text_output_protocol {
struct { struct {
void *reset; void *reset;
......
...@@ -19,7 +19,8 @@ enum efi_cmdline_option { ...@@ -19,7 +19,8 @@ enum efi_cmdline_option {
EFI_CMDLINE_NONE, EFI_CMDLINE_NONE,
EFI_CMDLINE_MODE_NUM, EFI_CMDLINE_MODE_NUM,
EFI_CMDLINE_RES, EFI_CMDLINE_RES,
EFI_CMDLINE_AUTO EFI_CMDLINE_AUTO,
EFI_CMDLINE_LIST
}; };
static struct { static struct {
...@@ -100,6 +101,19 @@ static bool parse_auto(char *option, char **next) ...@@ -100,6 +101,19 @@ static bool parse_auto(char *option, char **next)
return true; return true;
} }
static bool parse_list(char *option, char **next)
{
if (!strstarts(option, "list"))
return false;
option += strlen("list");
if (*option && *option++ != ',')
return false;
cmdline.option = EFI_CMDLINE_LIST;
*next = option;
return true;
}
void efi_parse_option_graphics(char *option) void efi_parse_option_graphics(char *option)
{ {
while (*option) { while (*option) {
...@@ -109,6 +123,8 @@ void efi_parse_option_graphics(char *option) ...@@ -109,6 +123,8 @@ void efi_parse_option_graphics(char *option)
continue; continue;
if (parse_auto(option, &option)) if (parse_auto(option, &option))
continue; continue;
if (parse_list(option, &option))
continue;
while (*option && *option++ != ',') while (*option && *option++ != ',')
; ;
...@@ -290,6 +306,82 @@ static u32 choose_mode_auto(efi_graphics_output_protocol_t *gop) ...@@ -290,6 +306,82 @@ static u32 choose_mode_auto(efi_graphics_output_protocol_t *gop)
return best_mode; return best_mode;
} }
static u32 choose_mode_list(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;
efi_pixel_bitmask_t pi;
u32 m, w, h;
u8 d;
const char *dstr;
bool valid;
efi_input_key_t key;
mode = efi_table_attr(gop, mode);
cur_mode = efi_table_attr(mode, mode);
max_mode = efi_table_attr(mode, max_mode);
efi_printk("Available graphics modes are 0-%u\n", max_mode-1);
efi_puts(" * = current mode\n"
" - = unusable mode\n");
for (m = 0; m < max_mode; m++) {
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);
valid = !(pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX);
d = 0;
switch (pf) {
case PIXEL_RGB_RESERVED_8BIT_PER_COLOR:
dstr = "rgb";
break;
case PIXEL_BGR_RESERVED_8BIT_PER_COLOR:
dstr = "bgr";
break;
case PIXEL_BIT_MASK:
dstr = "";
d = pixel_bpp(pf, pi);
break;
case PIXEL_BLT_ONLY:
dstr = "blt";
break;
default:
dstr = "xxx";
break;
}
efi_printk("Mode %3u %c%c: Resolution %ux%u-%s%.0hhu\n",
m,
m == cur_mode ? '*' : ' ',
!valid ? '-' : ' ',
w, h, dstr, d);
}
efi_puts("\nPress any key to continue (or wait 10 seconds)\n");
status = efi_wait_for_key(10 * EFI_USEC_PER_SEC, &key);
if (status != EFI_SUCCESS && status != EFI_TIMEOUT) {
efi_err("Unable to read key, continuing in 10 seconds\n");
efi_bs_call(stall, 10 * EFI_USEC_PER_SEC);
}
return cur_mode;
}
static void set_mode(efi_graphics_output_protocol_t *gop) static void set_mode(efi_graphics_output_protocol_t *gop)
{ {
efi_graphics_output_protocol_mode_t *mode; efi_graphics_output_protocol_mode_t *mode;
...@@ -305,6 +397,9 @@ static void set_mode(efi_graphics_output_protocol_t *gop) ...@@ -305,6 +397,9 @@ static void set_mode(efi_graphics_output_protocol_t *gop)
case EFI_CMDLINE_AUTO: case EFI_CMDLINE_AUTO:
new_mode = choose_mode_auto(gop); new_mode = choose_mode_auto(gop);
break; break;
case EFI_CMDLINE_LIST:
new_mode = choose_mode_list(gop);
break;
default: default:
return; return;
} }
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1))) #define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1)))
#define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1))) #define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1)))
#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1))) #define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1)))
#define EFI_TIMEOUT (18 | (1UL << (BITS_PER_LONG-1)))
#define EFI_ABORTED (21 | (1UL << (BITS_PER_LONG-1))) #define EFI_ABORTED (21 | (1UL << (BITS_PER_LONG-1)))
#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1))) #define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment