Skip to content

Commit 68d4b8a

Browse files
committed
boot/efi: add console-mode boot option to change resolution
The new boot option allows changing the display console mode to some new display resolution. Usage: in systemd-boot configuration file loader/loader.conf add one of: console-mode <number> console-mode auto console-mode max console-mode keep Where number can be: 1) 0: UEFI standard 80x25 mode 2) 1: 80x50 mode, if supported by device 3) 2 or greater: some non-standard device mode, if supported When using the auto mode, systemd-boot will try to find a reasonable mode automatically using some heuristic. Current implementation tries to switch console mode to mode 2 if it exists, mode 1 if it exists, else mode 0. Mode 2 is the first non standard mode provided by the firmware developer and it's assumed to be a reasonable mode. The max mode adds support for switching to the highest numbered console mode, whatever mode that would be in the system. The maximum mode being the last one implemented by the firmware provider should be a reasonable mode. The keep mode is the default and is only included for completeness. With this parameter, the user explicitly states and can be assured that systemd-boot will not change console mode. Note: patch includes a workaround for mode 1, that may not exist in EDK2 OVFM and results in a buggy text mode when requested.
1 parent cf6e1e6 commit 68d4b8a

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

src/boot/efi/boot.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ typedef struct {
6969
CHAR16 *entry_oneshot;
7070
CHAR16 *options_edit;
7171
BOOLEAN no_editor;
72+
UINTN console_mode;
73+
enum console_mode_change_type console_mode_change;
7274
} Config;
7375

7476
static VOID cursor_left(UINTN *cursor, UINTN *first) {
@@ -491,6 +493,7 @@ static BOOLEAN menu_run(Config *config, ConfigEntry **chosen_entry, CHAR16 *load
491493
BOOLEAN exit = FALSE;
492494
BOOLEAN run = TRUE;
493495
BOOLEAN wait = FALSE;
496+
BOOLEAN cleared_screen = FALSE;
494497

495498
graphics_mode(FALSE);
496499
uefi_call_wrapper(ST->ConIn->Reset, 2, ST->ConIn, FALSE);
@@ -499,7 +502,18 @@ static BOOLEAN menu_run(Config *config, ConfigEntry **chosen_entry, CHAR16 *load
499502

500503
/* draw a single character to make ClearScreen work on some firmware */
501504
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L" ");
502-
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
505+
506+
if (config->console_mode_change != CONSOLE_MODE_KEEP) {
507+
err = console_set_mode(&config->console_mode, config->console_mode_change);
508+
if (!EFI_ERROR(err))
509+
cleared_screen = TRUE;
510+
}
511+
512+
if (!cleared_screen)
513+
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
514+
515+
if (config->console_mode_change != CONSOLE_MODE_KEEP && EFI_ERROR(err))
516+
Print(L"Error switching console mode to %ld: %r.\r", (UINT64)config->console_mode, err);
503517

504518
err = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max);
505519
if (EFI_ERROR(err)) {
@@ -1008,6 +1022,26 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
10081022
continue;
10091023
config->no_editor = !on;
10101024
}
1025+
1026+
if (strcmpa((CHAR8 *)"console-mode", key) == 0) {
1027+
CHAR16 *s;
1028+
1029+
if (strcmpa((CHAR8 *)"auto", value) == 0)
1030+
config->console_mode_change = CONSOLE_MODE_AUTO;
1031+
else if (strcmpa((CHAR8 *)"max", value) == 0)
1032+
config->console_mode_change = CONSOLE_MODE_MAX;
1033+
else if (strcmpa((CHAR8 *)"keep", value) == 0)
1034+
config->console_mode_change = CONSOLE_MODE_KEEP;
1035+
else {
1036+
s = stra_to_str(value);
1037+
config->console_mode = Atoi(s);
1038+
config->console_mode_change = CONSOLE_MODE_SET;
1039+
FreePool(s);
1040+
}
1041+
1042+
continue;
1043+
}
1044+
10111045
}
10121046
}
10131047

src/boot/efi/console.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,48 @@ EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) {
134134
*key = KEYPRESS(0, k.ScanCode, k.UnicodeChar);
135135
return 0;
136136
}
137+
138+
static EFI_STATUS change_mode(UINTN mode) {
139+
EFI_STATUS err;
140+
141+
err = uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, mode);
142+
143+
/* Special case mode 1: when using OVMF and qemu, setting it returns error
144+
* and breaks console output. */
145+
if (EFI_ERROR(err) && mode == 1)
146+
uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, (UINTN)0);
147+
148+
return err;
149+
}
150+
151+
static EFI_STATUS mode_auto(UINTN *mode) {
152+
/* Mode number 2 is first non standard mode, which is provided by
153+
* the device manufacturer, so it should be a good mode.
154+
* Note: MaxMode is the number of modes, not the last mode. */
155+
if (ST->ConOut->Mode->MaxMode > 2)
156+
*mode = 2;
157+
/* Try again with mode different than zero (assume user requests
158+
* auto mode due to some problem with mode zero). */
159+
else if (ST->ConOut->Mode->MaxMode == 2)
160+
*mode = 1;
161+
/* Else force mode change to zero. */
162+
else
163+
*mode = 0;
164+
165+
return change_mode(*mode);
166+
}
167+
168+
EFI_STATUS console_set_mode(UINTN *mode, enum console_mode_change_type how) {
169+
if (how == CONSOLE_MODE_AUTO)
170+
return mode_auto(mode);
171+
172+
if (how == CONSOLE_MODE_MAX) {
173+
/* Note: MaxMode is the number of modes, not the last mode. */
174+
if (ST->ConOut->Mode->MaxMode > 0)
175+
*mode = ST->ConOut->Mode->MaxMode-1;
176+
else
177+
*mode = 0;
178+
}
179+
180+
return change_mode(*mode);
181+
}

src/boot/efi/console.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,13 @@
2929
#define KEYCHAR(k) ((k) & 0xffff)
3030
#define CHAR_CTRL(c) ((c) - 'a' + 1)
3131

32+
enum console_mode_change_type {
33+
CONSOLE_MODE_KEEP = 0,
34+
CONSOLE_MODE_SET,
35+
CONSOLE_MODE_AUTO,
36+
CONSOLE_MODE_MAX,
37+
};
38+
3239
EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait);
40+
EFI_STATUS console_set_mode(UINTN *mode, enum console_mode_change_type how);
3341
#endif

0 commit comments

Comments
 (0)