Skip to content

Commit

Permalink
MokManager: console mode modification for hi-dpi screen devices
Browse files Browse the repository at this point in the history
There are lots of hi-dpi laptops nowadays, as doing mok enrollment, the font
is too small to see.
https://bugs.launchpad.net/ubuntu/+source/shim/+bug/1822043

This patch checks if the resolution is larger than Full HD (1920x1080) and
current console output columns and rows is in a good mode. Then swith the
console output to a better mode.

Signed-off-by: Ivan Hu <ivan.hu@canonical.com>
Upstream-commit-id: cf05af6
  • Loading branch information
Ivanhu5866 authored and vathpela committed Jul 24, 2020
1 parent 9f80be9 commit 55163bc
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 1 deletion.
2 changes: 2 additions & 0 deletions MokManager.c
Original file line number Diff line number Diff line change
Expand Up @@ -2560,6 +2560,8 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE * systab)

setup_rand();

console_mode_handle();

efi_status = check_mok_request(image_handle);

console_fini();
Expand Down
2 changes: 2 additions & 0 deletions include/console.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ void
console_notify(CHAR16 *string);
void
console_reset(void);
void
console_mode_handle(void);
#define NOSEL 0x7fffffff

typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL;
Expand Down
161 changes: 160 additions & 1 deletion lib/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,166 @@ console_notify(CHAR16 *string)
console_alertbox(str_arr);
}

#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
void
console_save_and_set_mode(SIMPLE_TEXT_OUTPUT_MODE * SavedMode)
{
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;

if (!SavedMode) {
console_print(L"Invalid parameter: SavedMode\n");
return;
}

CopyMem(SavedMode, co->Mode, sizeof(SIMPLE_TEXT_OUTPUT_MODE));
co->EnableCursor(co, FALSE);
co->SetAttribute(co, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
}

void
console_restore_mode(SIMPLE_TEXT_OUTPUT_MODE * SavedMode)
{
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;

co->EnableCursor(co, SavedMode->CursorVisible);
co->SetCursorPosition(co, SavedMode->CursorColumn,
SavedMode->CursorRow);
co->SetAttribute(co, SavedMode->Attribute);
}

int
console_countdown(CHAR16* title, const CHAR16* message, int timeout)
{
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
SIMPLE_INPUT_INTERFACE *ci = ST->ConIn;
SIMPLE_TEXT_OUTPUT_MODE SavedMode;
EFI_INPUT_KEY key;
EFI_STATUS efi_status;
UINTN cols, rows;
CHAR16 *titles[2];
int wait = 10000000;

console_save_and_set_mode(&SavedMode);

titles[0] = title;
titles[1] = NULL;

console_print_box_at(titles, -1, 0, 0, -1, -1, 1, 1);

co->QueryMode(co, co->Mode->Mode, &cols, &rows);

console_print_at((cols - StrLen(message)) / 2, rows / 2, message);
while (1) {
if (timeout > 1)
console_print_at(2, rows - 3,
L"Booting in %d seconds ",
timeout);
else if (timeout)
console_print_at(2, rows - 3,
L"Booting in %d second ",
timeout);

efi_status = WaitForSingleEvent(ci->WaitForKey, wait);
if (efi_status != EFI_TIMEOUT) {
/* Clear the key in the queue */
ci->ReadKeyStroke(ci, &key);
break;
}

timeout--;
if (!timeout)
break;
}

console_restore_mode(&SavedMode);

return timeout;
}

#define HORIZONTAL_MAX_OK 1920
#define VERTICAL_MAX_OK 1080
#define COLUMNS_MAX_OK 200
#define ROWS_MAX_OK 100

void
console_mode_handle(VOID)
{
SIMPLE_TEXT_OUTPUT_INTERFACE *co = ST->ConOut;
EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;

UINTN mode_set;
UINTN rows = 0, columns = 0;
EFI_STATUS efi_status = EFI_SUCCESS;

efi_status = gBS->LocateProtocol(&gop_guid, NULL, (void **)&gop);
if (EFI_ERROR(efi_status)) {
console_error(L"Locate graphic output protocol fail", efi_status);
return;
}

Info = gop->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 original mode and return */
return;
}

efi_status = co->QueryMode(co, co->Mode->Mode, &columns, &rows);
if (EFI_ERROR(efi_status)) {
console_error(L"Console query mode fail", efi_status);
return;
}

/*
* Verify current console output to check if the character columns and
* rows in a good mode.
*/
if (columns <= COLUMNS_MAX_OK && rows <= ROWS_MAX_OK) {
/* keep original mode and return */
return;
}

if (!console_text_mode)
setup_console(1);

co->Reset(co, TRUE);

/*
* If we reached here, then we have a high resolution screen and the
* text too small. 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.
*/
if (co->Mode->MaxMode > 2)
mode_set = 2;
else
mode_set = 0;

efi_status = co->SetMode(co, mode_set);
if (EFI_ERROR(efi_status) && mode_set != 0) {
/*
* Set to 0 mode which is required that all output devices
* support at least 80x25 text mode.
*/
mode_set = 0;
efi_status = co->SetMode(co, mode_set);
}

co->ClearScreen(co);

if (EFI_ERROR(efi_status)) {
console_error(L"Console set mode fail", efi_status);
}

return;
}

/* Copy of gnu-efi-3.0 with the added secure boot strings */
static struct {
Expand Down

0 comments on commit 55163bc

Please sign in to comment.