diff --git a/src/boot/boot.c b/src/boot/boot.c index 0c88b05a41..b168eba01c 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -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); diff --git a/src/boot/efi-string.c b/src/boot/efi-string.c index 8e2c73d84d..f051b5dd88 100644 --- a/src/boot/efi-string.c +++ b/src/boot/efi-string.c @@ -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); diff --git a/src/boot/secure-boot.c b/src/boot/secure-boot.c index a7bac8bf08..3b3715d899 100644 --- a/src/boot/secure-boot.c +++ b/src/boot/secure-boot.c @@ -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, diff --git a/src/boot/util.c b/src/boot/util.c index 5d439430b8..92da63fc0f 100644 --- a/src/boot/util.c +++ b/src/boot/util.c @@ -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); } diff --git a/src/boot/util.h b/src/boot/util.h index e7a3ba0303..ef017f45fa 100644 --- a/src/boot/util.h +++ b/src/boot/util.h @@ -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);