efi_loader: Fix serial console size detection
authorMatthias Brugger <mbrugger@suse.com>
Tue, 5 Mar 2019 11:50:18 +0000 (12:50 +0100)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Sun, 10 Mar 2019 18:56:59 +0000 (19:56 +0100)
Function term_read_reply tries to read from the serial console until
the end_char was read. This can hang forever if we are, for some reason,
not able to read the full response (e.g. serial buffer too small,
frame error). This patch moves the timeout detection into
term_read_reply() to assure we will make progress.

Fixes: 6bb591f704 ("efi_loader: query serial console size reliably")
Signed-off-by: Matthias Brugger <mbrugger@suse.com>
Throw missing error when an incomplete reply for the cursor position is
received.

Change type of argument of term_get_char() *s32. This renders the function
reusable in efi_cin_read_key().

Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
lib/efi_loader/efi_console.c

index 66c33a551d5d8edd61a87028166d6aaf1073c874..8e0965bfc8941465580900826f8e8bc8aeac137c 100644 (file)
@@ -62,6 +62,21 @@ static struct simple_text_output_mode efi_con_mode = {
        .cursor_visible = 1,
 };
 
+static int term_get_char(s32 *c)
+{
+       u64 timeout;
+
+       /* Wait up to 100 ms for a character */
+       timeout = timer_get_us() + 100000;
+
+       while (!tstc())
+               if (timer_get_us() > timeout)
+                       return 1;
+
+       *c = getc();
+       return 0;
+}
+
 /*
  * Receive and parse a reply from the terminal.
  *
@@ -72,34 +87,36 @@ static struct simple_text_output_mode efi_con_mode = {
  */
 static int term_read_reply(int *n, int num, char end_char)
 {
-       char c;
+       s32 c;
        int i = 0;
 
-       c = getc();
-       if (c != cESC)
+       if (term_get_char(&c) || c != cESC)
                return -1;
-       c = getc();
-       if (c != '[')
+
+       if (term_get_char(&c) || c != '[')
                return -1;
 
        n[0] = 0;
        while (1) {
-               c = getc();
-               if (c == ';') {
-                       i++;
-                       if (i >= num)
+               if (!term_get_char(&c)) {
+                       if (c == ';') {
+                               i++;
+                               if (i >= num)
+                                       return -1;
+                               n[i] = 0;
+                               continue;
+                       } else if (c == end_char) {
+                               break;
+                       } else if (c > '9' || c < '0') {
                                return -1;
-                       n[i] = 0;
-                       continue;
-               } else if (c == end_char) {
-                       break;
-               } else if (c > '9' || c < '0') {
+                       }
+
+                       /* Read one more decimal position */
+                       n[i] *= 10;
+                       n[i] += c - '0';
+               } else {
                        return -1;
                }
-
-               /* Read one more decimal position */
-               n[i] *= 10;
-               n[i] += c - '0';
        }
        if (i != num - 1)
                return -1;
@@ -196,7 +213,6 @@ static int query_console_serial(int *rows, int *cols)
 {
        int ret = 0;
        int n[2];
-       u64 timeout;
 
        /* Empty input buffer */
        while (tstc())
@@ -216,14 +232,6 @@ static int query_console_serial(int *rows, int *cols)
               ESC "[999;999H"  /* Move to bottom right corner */
               ESC "[6n");      /* Query cursor position */
 
-       /* Allow up to one second for a response */
-       timeout = timer_get_us() + 1000000;
-       while (!tstc())
-               if (timer_get_us() > timeout) {
-                       ret = -1;
-                       goto out;
-               }
-
        /* Read {rows,cols} */
        if (term_read_reply(n, 2, 'R')) {
                ret = 1;