A configfile can run before its target selects visible output. Clearing the EFI 
console immediately erases the firmware splash even when the target continues 
with a hidden-menu autoboot.

Keep a pending clear on each inactive output terminal and consume it when that 
terminal prepares for visible output. Active terminals retain the existing 
immediate clear behaviour. This also prepares output before verbose sleep saves 
its cursor position.

Signed-off-by: Sean Rhodes <[email protected]>
---
 grub-core/commands/configfile.c |  3 ++-
 grub-core/commands/sleep.c      |  4 ++++
 grub-core/normal/term.c         | 35 +++++++++++++++++++++++++++++++++
 grub-core/term/efi/console.c    | 19 ++++++++++++++++++
 include/grub/term.h             | 11 +++++++++++
 5 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/grub-core/commands/configfile.c b/grub-core/commands/configfile.c
index f2d2abb..67bf5b1 100644
--- a/grub-core/commands/configfile.c
+++ b/grub-core/commands/configfile.c
@@ -37,8 +37,9 @@ grub_cmd_source (grub_command_t cmd, int argc, char **args)
   extractor = (cmd->name[0] == 'e');
   new_env = (cmd->name[extractor ? sizeof ("extract_entries_") - 1 : 0] == 
'c');
 
+  /* An uninitialized terminal may still be displaying a firmware splash.  */
   if (new_env)
-    grub_cls ();
+    grub_cls_deferred ();
 
   if (new_env && !extractor)
     grub_env_context_open ();
diff --git a/grub-core/commands/sleep.c b/grub-core/commands/sleep.c
index a1370b7..be4f2ce 100644
--- a/grub-core/commands/sleep.c
+++ b/grub-core/commands/sleep.c
@@ -80,6 +80,10 @@ grub_cmd_sleep (grub_extcmd_context_t ctxt, int argc, char 
**args)
 
   grub_refresh ();
 
+  /* A pending clear must happen before the countdown saves its position.  */
+  if (state[0].set)
+    grub_term_prepare_output ();
+
   pos = grub_term_save_pos ();
 
   for (; n; n--)
diff --git a/grub-core/normal/term.c b/grub-core/normal/term.c
index c073eb4..dc47390 100644
--- a/grub-core/normal/term.c
+++ b/grub-core/normal/term.c
@@ -990,6 +990,9 @@ grub_print_ucs4 (const grub_uint32_t * str,
                 int margin_left, int margin_right,
                 struct grub_term_output *term)
 {
+  if (str == last_position)
+    return;
+
   print_ucs4_real (str, last_position, margin_left, margin_right,
                   term, 0, 0, 1, 0, -1, 0, 0, 0);
 }
@@ -1011,6 +1014,9 @@ grub_xnputs (const char *str, grub_size_t msg_len)
   int backlog = 0;
   grub_term_output_t term;
 
+  if (msg_len == 0)
+    return;
+
   grub_error_push ();
 
   unicode_str = grub_calloc (msg_len, sizeof (grub_uint32_t));
@@ -1096,3 +1102,32 @@ grub_cls (void)
       (term->cls) (term);
   }
 }
+
+void
+grub_cls_deferred (void)
+{
+  struct grub_term_output *term;
+
+  FOR_ACTIVE_TERM_OUTPUTS(term)
+  {
+    if (term->prepare && !(term->flags & GRUB_TERM_OUTPUT_ACTIVE))
+      term->flags |= GRUB_TERM_CLEAR_PENDING;
+    else if ((term->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug")))
+      {
+       grub_putcode ('\n', term);
+       grub_term_refresh (term);
+      }
+    else
+      grub_term_cls (term);
+  }
+}
+
+void
+grub_term_prepare_output (void)
+{
+  struct grub_term_output *term;
+
+  FOR_ACTIVE_TERM_OUTPUTS(term)
+    if (term->prepare)
+      term->prepare (term);
+}
diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
index 37c4e51..52308df 100644
--- a/grub-core/term/efi/console.c
+++ b/grub-core/term/efi/console.c
@@ -140,6 +140,9 @@ grub_console_setcursor (struct grub_term_output *term 
__attribute__ ((unused)),
 static grub_err_t
 grub_prepare_for_text_output (struct grub_term_output *term)
 {
+  grub_efi_simple_text_output_interface_t *o;
+  grub_efi_int32_t orig_attr;
+
   if (grub_efi_is_finished)
     return GRUB_ERR_BAD_DEVICE;
 
@@ -159,6 +162,18 @@ grub_prepare_for_text_output (struct grub_term_output 
*term)
   if (text_colorstate != GRUB_TERM_COLOR_UNDEFINED)
     grub_console_setcolorstate (term, text_colorstate);
   text_mode = GRUB_TEXT_MODE_AVAILABLE;
+  term->flags |= GRUB_TERM_OUTPUT_ACTIVE;
+
+  if (term->flags & GRUB_TERM_CLEAR_PENDING)
+    {
+      term->flags &= ~GRUB_TERM_CLEAR_PENDING;
+      o = grub_efi_system_table->con_out;
+      orig_attr = o->mode->attribute;
+      o->set_attributes (o, GRUB_EFI_BACKGROUND_BLACK);
+      o->clear_screen (o);
+      o->set_attributes (o, orig_attr);
+    }
+
   return GRUB_ERR_NONE;
 }
 
@@ -435,6 +450,7 @@ grub_console_cls (struct grub_term_output *term 
__attribute__ ((unused)))
   grub_efi_simple_text_output_interface_t *o;
   grub_efi_int32_t orig_attr;
 
+  term->flags &= ~GRUB_TERM_CLEAR_PENDING;
   if (grub_prepare_for_text_output (term) != GRUB_ERR_NONE)
     return;
 
@@ -448,6 +464,8 @@ grub_console_cls (struct grub_term_output *term 
__attribute__ ((unused)))
 static grub_err_t
 grub_efi_console_output_fini (struct grub_term_output *term)
 {
+  term->flags &= ~(GRUB_TERM_OUTPUT_ACTIVE | GRUB_TERM_CLEAR_PENDING);
+
   if (text_mode != GRUB_TEXT_MODE_AVAILABLE)
     return 0;
 
@@ -469,6 +487,7 @@ static struct grub_term_output grub_console_term_output =
   {
     .name = "console",
     .fini = grub_efi_console_output_fini,
+    .prepare = grub_prepare_for_text_output,
     .putchar = grub_console_putchar,
     .getwh = grub_console_getwh,
     .getxy = grub_console_getxy,
diff --git a/include/grub/term.h b/include/grub/term.h
index 7f1a14c..fd08f6f 100644
--- a/include/grub/term.h
+++ b/include/grub/term.h
@@ -102,6 +102,10 @@ grub_term_color_state;
 #define GRUB_TERM_NO_EDIT              (1 << 1)
 /* Set when the terminal cannot do fancy things.  */
 #define GRUB_TERM_DUMB                 (1 << 2)
+/* Visible output has initialized this terminal.  */
+#define GRUB_TERM_OUTPUT_ACTIVE                (1 << 8)
+/* Clear when the terminal is prepared for visible output.  */
+#define GRUB_TERM_CLEAR_PENDING                (1 << 9)
 /* Which encoding does terminal expect stream to be.  */
 #define GRUB_TERM_CODE_TYPE_SHIFT       3
 #define GRUB_TERM_CODE_TYPE_MASK               (7 << GRUB_TERM_CODE_TYPE_SHIFT)
@@ -184,6 +188,11 @@ struct grub_term_output
   /* Clean up the terminal.  */
   grub_err_t (*fini) (struct grub_term_output *term);
 
+  /* Prepare the terminal for visible output.  Implementations set
+     GRUB_TERM_OUTPUT_ACTIVE and consume GRUB_TERM_CLEAR_PENDING before
+     rendering.  */
+  grub_err_t (*prepare) (struct grub_term_output *term);
+
   /* Put a character. C is encoded in Unicode.  */
   void (*putchar) (struct grub_term_output *term,
                   const struct grub_unicode_glyph *c);
@@ -332,6 +341,8 @@ int EXPORT_FUNC(grub_getkey_noblock) (void);
 int EXPORT_FUNC(grub_getkeystatus) (void);
 int EXPORT_FUNC(grub_key_is_interrupt) (int key);
 void grub_cls (void);
+void grub_cls_deferred (void);
+void grub_term_prepare_output (void);
 void EXPORT_FUNC(grub_refresh) (void);
 void grub_puts_terminal (const char *str, struct grub_term_output *term);
 struct grub_term_coordinate *grub_term_save_pos (void);

_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to