]> git.sur5r.net Git - u-boot/blobdiff - lib/efi_loader/efi_console.c
avb2.0: add Android Verified Boot 2.0 library
[u-boot] / lib / efi_loader / efi_console.c
index 5d1a9a8081eeab0681caf546977c15e76e80e3a8..ce66c935ecbf7cff0eb019712c465c4cf2a7d2da 100644 (file)
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *  EFI application console interface
  *
  *  Copyright (c) 2016 Alexander Graf
- *
- *  SPDX-License-Identifier:     GPL-2.0+
  */
 
 #include <common.h>
@@ -13,8 +12,6 @@
 #include <stdio_dev.h>
 #include <video_console.h>
 
-static bool console_size_queried;
-
 #define EFI_COUT_MODE_2 2
 #define EFI_MAX_COUT_MODE 3
 
@@ -63,7 +60,15 @@ static struct simple_text_output_mode efi_con_mode = {
        .cursor_visible = 1,
 };
 
-static int term_read_reply(int *n, int maxnum, char end_char)
+/*
+ * Receive and parse a reply from the terminal.
+ *
+ * @n:         array of return values
+ * @num:       number of return values expected
+ * @end_char:  character indicating end of terminal message
+ * @return:    non-zero indicates error
+ */
+static int term_read_reply(int *n, int num, char end_char)
 {
        char c;
        int i = 0;
@@ -80,7 +85,7 @@ static int term_read_reply(int *n, int maxnum, char end_char)
                c = getc();
                if (c == ';') {
                        i++;
-                       if (i >= maxnum)
+                       if (i >= num)
                                return -1;
                        n[i] = 0;
                        continue;
@@ -94,6 +99,8 @@ static int term_read_reply(int *n, int maxnum, char end_char)
                n[i] *= 10;
                n[i] += c - '0';
        }
+       if (i != num - 1)
+               return -1;
 
        return 0;
 }
@@ -117,25 +124,36 @@ static efi_status_t EFIAPI efi_cout_output_string(
 
        unsigned int n16 = utf16_strlen(string);
        char buf[MAX_UTF8_PER_UTF16 * n16 + 1];
-       char *p;
+       u16 *p;
 
        *utf16_to_utf8((u8 *)buf, string, n16) = '\0';
 
        fputs(stdout, buf);
 
-       for (p = buf; *p; p++) {
+       /*
+        * Update the cursor position.
+        *
+        * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
+        * and U000D. All other characters, including control characters
+        * U+0007 (bel) and U+0009 (tab), have to increase the column by one.
+        */
+       for (p = string; *p; ++p) {
                switch (*p) {
-               case '\r':   /* carriage-return */
-                       con->cursor_column = 0;
+               case '\b':      /* U+0008, backspace */
+                       con->cursor_column = max(0, con->cursor_column - 1);
                        break;
-               case '\n':   /* newline */
+               case '\n':      /* U+000A, newline */
                        con->cursor_column = 0;
                        con->cursor_row++;
                        break;
-               case '\t':   /* tab, assume 8 char align */
+               case '\r':      /* U+000D, carriage-return */
+                       con->cursor_column = 0;
                        break;
-               case '\b':   /* backspace */
-                       con->cursor_column = max(0, con->cursor_column - 1);
+               case 0xd800 ... 0xdbff:
+                       /*
+                        * Ignore high surrogates, we do not want to count a
+                        * Unicode character twice.
+                        */
                        break;
                default:
                        con->cursor_column++;
@@ -195,6 +213,51 @@ static int query_console_serial(int *rows, int *cols)
        return 0;
 }
 
+/*
+ * Update the mode table.
+ *
+ * By default the only mode available is 80x25. If the console has at least 50
+ * lines, enable mode 80x50. If we can query the console size and it is neither
+ * 80x25 nor 80x50, set it as an additional mode.
+ */
+static void query_console_size(void)
+{
+       const char *stdout_name = env_get("stdout");
+       int rows = 25, cols = 80;
+
+       if (stdout_name && !strcmp(stdout_name, "vidconsole") &&
+           IS_ENABLED(CONFIG_DM_VIDEO)) {
+               struct stdio_dev *stdout_dev =
+                       stdio_get_by_name("vidconsole");
+               struct udevice *dev = stdout_dev->priv;
+               struct vidconsole_priv *priv =
+                       dev_get_uclass_priv(dev);
+               rows = priv->rows;
+               cols = priv->cols;
+       } else if (query_console_serial(&rows, &cols)) {
+               return;
+       }
+
+       /* Test if we can have Mode 1 */
+       if (cols >= 80 && rows >= 50) {
+               efi_cout_modes[1].present = 1;
+               efi_con_mode.max_mode = 2;
+       }
+
+       /*
+        * Install our mode as mode 2 if it is different
+        * than mode 0 or 1 and set it as the currently selected mode
+        */
+       if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
+           !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
+               efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
+               efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
+               efi_cout_modes[EFI_COUT_MODE_2].present = 1;
+               efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
+               efi_con_mode.mode = EFI_COUT_MODE_2;
+       }
+}
+
 static efi_status_t EFIAPI efi_cout_query_mode(
                        struct efi_simple_text_output_protocol *this,
                        unsigned long mode_number, unsigned long *columns,
@@ -202,52 +265,12 @@ static efi_status_t EFIAPI efi_cout_query_mode(
 {
        EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
 
-       if (!console_size_queried) {
-               const char *stdout_name = env_get("stdout");
-               int rows, cols;
-
-               console_size_queried = true;
-
-               if (stdout_name && !strcmp(stdout_name, "vidconsole") &&
-                   IS_ENABLED(CONFIG_DM_VIDEO)) {
-                       struct stdio_dev *stdout_dev =
-                               stdio_get_by_name("vidconsole");
-                       struct udevice *dev = stdout_dev->priv;
-                       struct vidconsole_priv *priv =
-                               dev_get_uclass_priv(dev);
-                       rows = priv->rows;
-                       cols = priv->cols;
-               } else if (query_console_serial(&rows, &cols)) {
-                       goto out;
-               }
-
-               /* Test if we can have Mode 1 */
-               if (cols >= 80 && rows >= 50) {
-                       efi_cout_modes[1].present = 1;
-                       efi_con_mode.max_mode = 2;
-               }
-
-               /*
-                * Install our mode as mode 2 if it is different
-                * than mode 0 or 1 and set it  as the currently selected mode
-                */
-               if (!cout_mode_matches(&efi_cout_modes[0], rows, cols) &&
-                   !cout_mode_matches(&efi_cout_modes[1], rows, cols)) {
-                       efi_cout_modes[EFI_COUT_MODE_2].columns = cols;
-                       efi_cout_modes[EFI_COUT_MODE_2].rows = rows;
-                       efi_cout_modes[EFI_COUT_MODE_2].present = 1;
-                       efi_con_mode.max_mode = EFI_MAX_COUT_MODE;
-                       efi_con_mode.mode = EFI_COUT_MODE_2;
-               }
-       }
-
        if (mode_number >= efi_con_mode.max_mode)
                return EFI_EXIT(EFI_UNSUPPORTED);
 
        if (efi_cout_modes[mode_number].present != 1)
                return EFI_EXIT(EFI_UNSUPPORTED);
 
-out:
        if (columns)
                *columns = efi_cout_modes[mode_number].columns;
        if (rows)
@@ -555,6 +578,9 @@ int efi_console_register(void)
        struct efi_object *efi_console_output_obj;
        struct efi_object *efi_console_input_obj;
 
+       /* Set up mode information */
+       query_console_size();
+
        /* Create handles */
        r = efi_create_handle((efi_handle_t *)&efi_console_output_obj);
        if (r != EFI_SUCCESS)