sd-boot: terminal handling tweaks (#39026)

Let's make sd-boot's terminal handling a bit cleaner, to the point that
uefi's weird handling allows this.
This commit is contained in:
Lennart Poettering
2025-09-24 14:40:38 +02:00
committed by GitHub
5 changed files with 52 additions and 5 deletions

View File

@@ -495,8 +495,9 @@ static bool menu_run(
ST->ConIn->Reset(ST->ConIn, false);
ST->ConOut->EnableCursor(ST->ConOut, false);
/* draw a single character to make ClearScreen work on some firmware */
ST->ConOut->OutputString(ST->ConOut, (char16_t *) u" ");
/* Draw a single character to the beginning of a line, in order to make ClearScreen() work on certain
* broken firmware. And let's immediately move back to the beginning of the line. */
printf("\r \r");
err = console_set_mode(config->console_mode_efivar != CONSOLE_MODE_KEEP ?
config->console_mode_efivar : config->console_mode);

View File

@@ -917,6 +917,37 @@ static bool handle_format_specifier(FormatContext *ctx, SpecifierContext *sp) {
}
}
#if SD_BOOT
static void output_string_safe(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *this, const char16_t *s) {
assert(this);
assert(s);
/* This is a color-conscious version of ST->ConOut->OutputString(). Whenever it encounters a newline
* character, it will reset the color to our default, because some UEFI implementations/terminals
* reset the color in that case, and we want our default color to remain in effect */
int32_t saved_attribute = ST->ConOut->Mode->Attribute;
for (;;) {
const char16_t *nl = strchr16(s, '\n');
if (!nl) /* No further newline */
return (void) ST->ConOut->OutputString(ST->ConOut, (char16_t*) s);
if (nl[1] == 0) { /* Newline is at the end of the string */
(void) ST->ConOut->OutputString(ST->ConOut, (char16_t*) s);
set_attribute_safe(saved_attribute);
return;
}
/* newline is in the middle of the string */
_cleanup_free_ char16_t *x = xstrndup16(s, nl - s + 1);
(void) ST->ConOut->OutputString(ST->ConOut, x);
set_attribute_safe(saved_attribute);
s = nl + 1;
}
}
#endif
/* printf_internal is largely compatible to userspace vasprintf. Any features omitted should trigger asserts.
*
* Supported:
@@ -983,7 +1014,7 @@ _printf_(2, 0) static char16_t *printf_internal(EFI_STATUS status, const char *f
}
#if SD_BOOT
ST->ConOut->OutputString(ST->ConOut, ctx.buf);
output_string_safe(ST->ConOut, ctx.buf);
#endif
return mfree(ctx.dyn_buf);

View File

@@ -105,6 +105,9 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool
timeout_sec--;
continue;
}
printf("\n");
if (err != EFI_SUCCESS)
return log_error_status(
err,

View File

@@ -195,16 +195,27 @@ EFI_STATUS file_read(
return file_handle_read(handle, offset, size, ret, ret_size);
}
void set_attribute_safe(size_t attr) {
/* Various UEFI implementations suppress color changes from a color to the same color. Often, we want
* to force out the color change though, hence change the color here once, and then back. We simply
* mark the color as bright for a moment, and then revert that. */
attr ^= 0x08;
ST->ConOut->SetAttribute(ST->ConOut, attr);
attr ^= 0x08;
ST->ConOut->SetAttribute(ST->ConOut, attr);
}
void print_at(size_t x, size_t y, size_t attr, const char16_t *str) {
assert(str);
ST->ConOut->SetCursorPosition(ST->ConOut, x, y);
ST->ConOut->SetAttribute(ST->ConOut, attr);
set_attribute_safe(attr);
ST->ConOut->OutputString(ST->ConOut, (char16_t *) str);
}
void clear_screen(size_t attr) {
log_wait();
ST->ConOut->SetAttribute(ST->ConOut, attr);
set_attribute_safe(attr);
ST->ConOut->ClearScreen(ST->ConOut);
}

View File

@@ -152,6 +152,7 @@ static inline void unload_imagep(EFI_HANDLE *image) {
#define GUID_FORMAT_VAL(g) (g).Data1, (g).Data2, (g).Data3, (g).Data4[0], (g).Data4[1], \
(g).Data4[2], (g).Data4[3], (g).Data4[4], (g).Data4[5], (g).Data4[6], (g).Data4[7]
void set_attribute_safe(size_t attr);
void print_at(size_t x, size_t y, size_t attr, const char16_t *str);
void clear_screen(size_t attr);