Merge pull request #8086 from hdante/sdboot-setmode-v2
This commit is contained in:
commit
48af1eb6ee
|
@ -827,6 +827,7 @@ static int install_loader_config(const char *esp_path) {
|
|||
}
|
||||
|
||||
fprintf(f, "#timeout 3\n");
|
||||
fprintf(f, "#console-mode keep\n");
|
||||
fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
|
||||
|
||||
r = fflush_sync_and_check(f);
|
||||
|
|
|
@ -71,6 +71,8 @@ typedef struct {
|
|||
BOOLEAN editor;
|
||||
BOOLEAN auto_entries;
|
||||
BOOLEAN auto_firmware;
|
||||
UINTN console_mode;
|
||||
enum console_mode_change_type console_mode_change;
|
||||
} Config;
|
||||
|
||||
static VOID cursor_left(UINTN *cursor, UINTN *first) {
|
||||
|
@ -497,6 +499,7 @@ static BOOLEAN menu_run(Config *config, ConfigEntry **chosen_entry, CHAR16 *load
|
|||
BOOLEAN exit = FALSE;
|
||||
BOOLEAN run = TRUE;
|
||||
BOOLEAN wait = FALSE;
|
||||
BOOLEAN cleared_screen = FALSE;
|
||||
|
||||
graphics_mode(FALSE);
|
||||
uefi_call_wrapper(ST->ConIn->Reset, 2, ST->ConIn, FALSE);
|
||||
|
@ -505,7 +508,18 @@ static BOOLEAN menu_run(Config *config, ConfigEntry **chosen_entry, CHAR16 *load
|
|||
|
||||
/* draw a single character to make ClearScreen work on some firmware */
|
||||
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L" ");
|
||||
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
|
||||
|
||||
if (config->console_mode_change != CONSOLE_MODE_KEEP) {
|
||||
err = console_set_mode(&config->console_mode, config->console_mode_change);
|
||||
if (!EFI_ERROR(err))
|
||||
cleared_screen = TRUE;
|
||||
}
|
||||
|
||||
if (!cleared_screen)
|
||||
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
|
||||
|
||||
if (config->console_mode_change != CONSOLE_MODE_KEEP && EFI_ERROR(err))
|
||||
Print(L"Error switching console mode to %ld: %r.\r", (UINT64)config->console_mode, err);
|
||||
|
||||
err = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max);
|
||||
if (EFI_ERROR(err)) {
|
||||
|
@ -1030,6 +1044,26 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
|
|||
continue;
|
||||
config->auto_firmware = on;
|
||||
}
|
||||
|
||||
if (strcmpa((CHAR8 *)"console-mode", key) == 0) {
|
||||
CHAR16 *s;
|
||||
|
||||
if (strcmpa((CHAR8 *)"auto", value) == 0)
|
||||
config->console_mode_change = CONSOLE_MODE_AUTO;
|
||||
else if (strcmpa((CHAR8 *)"max", value) == 0)
|
||||
config->console_mode_change = CONSOLE_MODE_MAX;
|
||||
else if (strcmpa((CHAR8 *)"keep", value) == 0)
|
||||
config->console_mode_change = CONSOLE_MODE_KEEP;
|
||||
else {
|
||||
s = stra_to_str(value);
|
||||
config->console_mode = Atoi(s);
|
||||
config->console_mode_change = CONSOLE_MODE_SET;
|
||||
FreePool(s);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
#include "console.h"
|
||||
#include "util.h"
|
||||
|
||||
#define SYSTEM_FONT_WIDTH 8
|
||||
#define SYSTEM_FONT_HEIGHT 19
|
||||
|
||||
#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
|
||||
{ 0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } }
|
||||
|
||||
|
@ -134,3 +137,105 @@ EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) {
|
|||
*key = KEYPRESS(0, k.ScanCode, k.UnicodeChar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static EFI_STATUS change_mode(UINTN mode) {
|
||||
EFI_STATUS err;
|
||||
|
||||
err = uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, mode);
|
||||
|
||||
/* Special case mode 1: when using OVMF and qemu, setting it returns error
|
||||
* and breaks console output. */
|
||||
if (EFI_ERROR(err) && mode == 1)
|
||||
uefi_call_wrapper(ST->ConOut->SetMode, 2, ST->ConOut, (UINTN)0);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static UINT64 text_area_from_font_size(void) {
|
||||
EFI_STATUS err;
|
||||
UINT64 text_area;
|
||||
UINTN rows, columns;
|
||||
|
||||
err = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &columns, &rows);
|
||||
if (EFI_ERROR(err)) {
|
||||
columns = 80;
|
||||
rows = 25;
|
||||
}
|
||||
|
||||
text_area = SYSTEM_FONT_WIDTH * SYSTEM_FONT_HEIGHT * (UINT64)rows * (UINT64)columns;
|
||||
|
||||
return text_area;
|
||||
}
|
||||
|
||||
static EFI_STATUS mode_auto(UINTN *mode) {
|
||||
const UINT32 HORIZONTAL_MAX_OK = 1920;
|
||||
const UINT32 VERTICAL_MAX_OK = 1080;
|
||||
const UINT64 VIEWPORT_RATIO = 10;
|
||||
UINT64 screen_area, text_area;
|
||||
EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
|
||||
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
|
||||
EFI_STATUS err;
|
||||
BOOLEAN keep = FALSE;
|
||||
|
||||
err = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
|
||||
if (!EFI_ERROR(err) && GraphicsOutput->Mode && GraphicsOutput->Mode->Info) {
|
||||
Info = GraphicsOutput->Mode->Info;
|
||||
|
||||
/* Start verifying if we are in a resolution larger than Full HD
|
||||
* (1920x1080). If we're not, assume we're in a good mode and do not
|
||||
* try to change it. */
|
||||
if (Info->HorizontalResolution <= HORIZONTAL_MAX_OK && Info->VerticalResolution <= VERTICAL_MAX_OK)
|
||||
keep = TRUE;
|
||||
/* For larger resolutions, calculate the ratio of the total screen
|
||||
* area to the text viewport area. If it's less than 10 times bigger,
|
||||
* then assume the text is readable and keep the text mode. */
|
||||
else {
|
||||
screen_area = (UINT64)Info->HorizontalResolution * (UINT64)Info->VerticalResolution;
|
||||
text_area = text_area_from_font_size();
|
||||
|
||||
if (text_area != 0 && screen_area/text_area < VIEWPORT_RATIO)
|
||||
keep = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (keep) {
|
||||
/* Just clear the screen instead of changing the mode and return. */
|
||||
*mode = ST->ConOut->Mode->Mode;
|
||||
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/* If we reached here, then we have a high resolution screen and the text
|
||||
* viewport is less than 10% the screen area, so the firmware developer
|
||||
* screwed up. Try to switch to a better mode. Mode number 2 is first non
|
||||
* standard mode, which is provided by the device manufacturer, so it should
|
||||
* be a good mode.
|
||||
* Note: MaxMode is the number of modes, not the last mode. */
|
||||
if (ST->ConOut->Mode->MaxMode > 2)
|
||||
*mode = 2;
|
||||
/* Try again with mode different than zero (assume user requests
|
||||
* auto mode due to some problem with mode zero). */
|
||||
else if (ST->ConOut->Mode->MaxMode == 2)
|
||||
*mode = 1;
|
||||
/* Else force mode change to zero. */
|
||||
else
|
||||
*mode = 0;
|
||||
|
||||
return change_mode(*mode);
|
||||
}
|
||||
|
||||
EFI_STATUS console_set_mode(UINTN *mode, enum console_mode_change_type how) {
|
||||
if (how == CONSOLE_MODE_AUTO)
|
||||
return mode_auto(mode);
|
||||
|
||||
if (how == CONSOLE_MODE_MAX) {
|
||||
/* Note: MaxMode is the number of modes, not the last mode. */
|
||||
if (ST->ConOut->Mode->MaxMode > 0)
|
||||
*mode = ST->ConOut->Mode->MaxMode-1;
|
||||
else
|
||||
*mode = 0;
|
||||
}
|
||||
|
||||
return change_mode(*mode);
|
||||
}
|
||||
|
|
|
@ -29,5 +29,13 @@
|
|||
#define KEYCHAR(k) ((k) & 0xffff)
|
||||
#define CHAR_CTRL(c) ((c) - 'a' + 1)
|
||||
|
||||
enum console_mode_change_type {
|
||||
CONSOLE_MODE_KEEP = 0,
|
||||
CONSOLE_MODE_SET,
|
||||
CONSOLE_MODE_AUTO,
|
||||
CONSOLE_MODE_MAX,
|
||||
};
|
||||
|
||||
EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait);
|
||||
EFI_STATUS console_set_mode(UINTN *mode, enum console_mode_change_type how);
|
||||
#endif
|
||||
|
|
|
@ -206,6 +206,8 @@ int boot_loader_read_conf(const char *path, BootConfig *config) {
|
|||
r = free_and_strdup(&config->auto_entries, p);
|
||||
else if (streq(buf, "auto-firmware"))
|
||||
r = free_and_strdup(&config->auto_firmware, p);
|
||||
else if (streq(buf, "console-mode"))
|
||||
r = free_and_strdup(&config->console_mode, p);
|
||||
else {
|
||||
log_notice("%s:%u: Unknown line \"%s\"", path, line, field);
|
||||
continue;
|
||||
|
|
|
@ -42,6 +42,7 @@ typedef struct BootConfig {
|
|||
char *editor;
|
||||
char *auto_entries;
|
||||
char *auto_firmware;
|
||||
char *console_mode;
|
||||
|
||||
char *entry_oneshot;
|
||||
char *entry_default;
|
||||
|
|
Loading…
Reference in a new issue