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

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.edu


Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
parent 9b47c527
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -63,4 +63,9 @@ auto
        with the highest resolution, it will choose one with the highest color
        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>
+35 −0
Original line number Diff line number Diff line
@@ -463,3 +463,38 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image,

	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;
}
+2 −0
Original line number Diff line number Diff line
@@ -323,6 +323,8 @@ union efi_simple_text_input_protocol {
	} mixed_mode;
};

efi_status_t efi_wait_for_key(unsigned long usec, efi_input_key_t *key);

union efi_simple_text_output_protocol {
	struct {
		void *reset;
+96 −1
Original line number Diff line number Diff line
@@ -19,7 +19,8 @@ enum efi_cmdline_option {
	EFI_CMDLINE_NONE,
	EFI_CMDLINE_MODE_NUM,
	EFI_CMDLINE_RES,
	EFI_CMDLINE_AUTO
	EFI_CMDLINE_AUTO,
	EFI_CMDLINE_LIST
};

static struct {
@@ -100,6 +101,19 @@ static bool parse_auto(char *option, char **next)
	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)
{
	while (*option) {
@@ -109,6 +123,8 @@ void efi_parse_option_graphics(char *option)
			continue;
		if (parse_auto(option, &option))
			continue;
		if (parse_list(option, &option))
			continue;

		while (*option && *option++ != ',')
			;
@@ -290,6 +306,82 @@ static u32 choose_mode_auto(efi_graphics_output_protocol_t *gop)
	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)
{
	efi_graphics_output_protocol_mode_t *mode;
@@ -305,6 +397,9 @@ static void set_mode(efi_graphics_output_protocol_t *gop)
	case EFI_CMDLINE_AUTO:
		new_mode = choose_mode_auto(gop);
		break;
	case EFI_CMDLINE_LIST:
		new_mode = choose_mode_list(gop);
		break;
	default:
		return;
	}
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#define EFI_WRITE_PROTECTED	( 8 | (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_TIMEOUT		(18 | (1UL << (BITS_PER_LONG-1)))
#define EFI_ABORTED		(21 | (1UL << (BITS_PER_LONG-1)))
#define EFI_SECURITY_VIOLATION	(26 | (1UL << (BITS_PER_LONG-1)))