Skip to content

Commit 14c574f

Browse files
nivedita76ardbiesheuvel
authored andcommitted
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: Arvind Sankar <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent 9b47c52 commit 14c574f

File tree

5 files changed

+139
-1
lines changed

5 files changed

+139
-1
lines changed

Documentation/fb/efifb.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,9 @@ auto
6363
with the highest resolution, it will choose one with the highest color
6464
depth.
6565

66+
list
67+
The EFI stub will list out all the display modes that are available. A
68+
specific mode can then be chosen using one of the above options for the
69+
next boot.
70+
6671
Edgar Hucek <[email protected]>

drivers/firmware/efi/libstub/efi-stub-helper.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,3 +463,38 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image,
463463

464464
return status;
465465
}
466+
467+
efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key)
468+
{
469+
efi_event_t events[2], timer;
470+
unsigned long index;
471+
efi_simple_text_input_protocol_t *con_in;
472+
efi_status_t status;
473+
474+
con_in = efi_table_attr(efi_system_table, con_in);
475+
if (!con_in)
476+
return EFI_UNSUPPORTED;
477+
efi_set_event_at(events, 0, efi_table_attr(con_in, wait_for_key));
478+
479+
status = efi_bs_call(create_event, EFI_EVT_TIMER, 0, NULL, NULL, &timer);
480+
if (status != EFI_SUCCESS)
481+
return status;
482+
483+
status = efi_bs_call(set_timer, timer, EfiTimerRelative,
484+
EFI_100NSEC_PER_USEC * usec);
485+
if (status != EFI_SUCCESS)
486+
return status;
487+
efi_set_event_at(events, 1, timer);
488+
489+
status = efi_bs_call(wait_for_event, 2, events, &index);
490+
if (status == EFI_SUCCESS) {
491+
if (index == 0)
492+
status = efi_call_proto(con_in, read_keystroke, key);
493+
else
494+
status = EFI_TIMEOUT;
495+
}
496+
497+
efi_bs_call(close_event, timer);
498+
499+
return status;
500+
}

drivers/firmware/efi/libstub/efistub.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ union efi_simple_text_input_protocol {
323323
} mixed_mode;
324324
};
325325

326+
efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key);
327+
326328
union efi_simple_text_output_protocol {
327329
struct {
328330
void *reset;

drivers/firmware/efi/libstub/gop.c

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ enum efi_cmdline_option {
1919
EFI_CMDLINE_NONE,
2020
EFI_CMDLINE_MODE_NUM,
2121
EFI_CMDLINE_RES,
22-
EFI_CMDLINE_AUTO
22+
EFI_CMDLINE_AUTO,
23+
EFI_CMDLINE_LIST
2324
};
2425

2526
static struct {
@@ -100,6 +101,19 @@ static bool parse_auto(char *option, char **next)
100101
return true;
101102
}
102103

104+
static bool parse_list(char *option, char **next)
105+
{
106+
if (!strstarts(option, "list"))
107+
return false;
108+
option += strlen("list");
109+
if (*option && *option++ != ',')
110+
return false;
111+
cmdline.option = EFI_CMDLINE_LIST;
112+
113+
*next = option;
114+
return true;
115+
}
116+
103117
void efi_parse_option_graphics(char *option)
104118
{
105119
while (*option) {
@@ -109,6 +123,8 @@ void efi_parse_option_graphics(char *option)
109123
continue;
110124
if (parse_auto(option, &option))
111125
continue;
126+
if (parse_list(option, &option))
127+
continue;
112128

113129
while (*option && *option++ != ',')
114130
;
@@ -290,6 +306,82 @@ static u32 choose_mode_auto(efi_graphics_output_protocol_t *gop)
290306
return best_mode;
291307
}
292308

309+
static u32 choose_mode_list(efi_graphics_output_protocol_t *gop)
310+
{
311+
efi_status_t status;
312+
313+
efi_graphics_output_protocol_mode_t *mode;
314+
efi_graphics_output_mode_info_t *info;
315+
unsigned long info_size;
316+
317+
u32 max_mode, cur_mode;
318+
int pf;
319+
efi_pixel_bitmask_t pi;
320+
u32 m, w, h;
321+
u8 d;
322+
const char *dstr;
323+
bool valid;
324+
efi_input_key_t key;
325+
326+
mode = efi_table_attr(gop, mode);
327+
328+
cur_mode = efi_table_attr(mode, mode);
329+
max_mode = efi_table_attr(mode, max_mode);
330+
331+
efi_printk("Available graphics modes are 0-%u\n", max_mode-1);
332+
efi_puts(" * = current mode\n"
333+
" - = unusable mode\n");
334+
for (m = 0; m < max_mode; m++) {
335+
status = efi_call_proto(gop, query_mode, m,
336+
&info_size, &info);
337+
if (status != EFI_SUCCESS)
338+
continue;
339+
340+
pf = info->pixel_format;
341+
pi = info->pixel_information;
342+
w = info->horizontal_resolution;
343+
h = info->vertical_resolution;
344+
345+
efi_bs_call(free_pool, info);
346+
347+
valid = !(pf == PIXEL_BLT_ONLY || pf >= PIXEL_FORMAT_MAX);
348+
d = 0;
349+
switch (pf) {
350+
case PIXEL_RGB_RESERVED_8BIT_PER_COLOR:
351+
dstr = "rgb";
352+
break;
353+
case PIXEL_BGR_RESERVED_8BIT_PER_COLOR:
354+
dstr = "bgr";
355+
break;
356+
case PIXEL_BIT_MASK:
357+
dstr = "";
358+
d = pixel_bpp(pf, pi);
359+
break;
360+
case PIXEL_BLT_ONLY:
361+
dstr = "blt";
362+
break;
363+
default:
364+
dstr = "xxx";
365+
break;
366+
}
367+
368+
efi_printk("Mode %3u %c%c: Resolution %ux%u-%s%.0hhu\n",
369+
m,
370+
m == cur_mode ? '*' : ' ',
371+
!valid ? '-' : ' ',
372+
w, h, dstr, d);
373+
}
374+
375+
efi_puts("\nPress any key to continue (or wait 10 seconds)\n");
376+
status = efi_wait_for_key(10 * EFI_USEC_PER_SEC, &key);
377+
if (status != EFI_SUCCESS && status != EFI_TIMEOUT) {
378+
efi_err("Unable to read key, continuing in 10 seconds\n");
379+
efi_bs_call(stall, 10 * EFI_USEC_PER_SEC);
380+
}
381+
382+
return cur_mode;
383+
}
384+
293385
static void set_mode(efi_graphics_output_protocol_t *gop)
294386
{
295387
efi_graphics_output_protocol_mode_t *mode;
@@ -305,6 +397,9 @@ static void set_mode(efi_graphics_output_protocol_t *gop)
305397
case EFI_CMDLINE_AUTO:
306398
new_mode = choose_mode_auto(gop);
307399
break;
400+
case EFI_CMDLINE_LIST:
401+
new_mode = choose_mode_list(gop);
402+
break;
308403
default:
309404
return;
310405
}

include/linux/efi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1)))
4040
#define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1)))
4141
#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1)))
42+
#define EFI_TIMEOUT (18 | (1UL << (BITS_PER_LONG-1)))
4243
#define EFI_ABORTED (21 | (1UL << (BITS_PER_LONG-1)))
4344
#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1)))
4445

0 commit comments

Comments
 (0)