From owner-svn-src-stable@freebsd.org Sun Dec 30 09:05:04 2018 Return-Path: Delivered-To: svn-src-stable@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id B5F4D141F011; Sun, 30 Dec 2018 09:05:03 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 5925975725; Sun, 30 Dec 2018 09:05:03 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4D8CC20BC5; Sun, 30 Dec 2018 09:05:03 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id wBU953pq037033; Sun, 30 Dec 2018 09:05:03 GMT (envelope-from tsoome@FreeBSD.org) Received: (from tsoome@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id wBU953FI037032; Sun, 30 Dec 2018 09:05:03 GMT (envelope-from tsoome@FreeBSD.org) Message-Id: <201812300905.wBU953FI037032@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: tsoome set sender to tsoome@FreeBSD.org using -f From: Toomas Soome Date: Sun, 30 Dec 2018 09:05:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r342617 - stable/12/stand/efi/libefi X-SVN-Group: stable-12 X-SVN-Commit-Author: tsoome X-SVN-Commit-Paths: stable/12/stand/efi/libefi X-SVN-Commit-Revision: 342617 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 5925975725 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.91 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.91)[-0.909,0]; NEURAL_HAM_LONG(-1.00)[-0.998,0] X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 30 Dec 2018 09:05:04 -0000 Author: tsoome Date: Sun Dec 30 09:05:02 2018 New Revision: 342617 URL: https://svnweb.freebsd.org/changeset/base/342617 Log: MFC r341329: loader.efi: fix EFI getchar() for multiple consoles This fix is ported from illumos (issue #9970), the analysis and initial implementation was done by John Levon. See also: https://www.illumos.org/issues/9970 Currently, efi_cons_getchar() will wait for a key. While this seems to make sense, the implementation of getchar() in common/console.c will loop across getchar() for all consoles without doing ischar() first. This means that if we've configured multiple consoles, we can't input into the serial, as getchar() will be sat waiting for input only from efi_console.c This patch does implement a bit more generic key buffer to support translation of input keys, and we use generic efi_readkey() to reduce duplication from calls from getchar() and poll(). Relnotes: yes Modified: stable/12/stand/efi/libefi/efi_console.c Directory Properties: stable/12/ (props changed) Modified: stable/12/stand/efi/libefi/efi_console.c ============================================================================== --- stable/12/stand/efi/libefi/efi_console.c Sun Dec 30 08:58:31 2018 (r342616) +++ stable/12/stand/efi/libefi/efi_console.c Sun Dec 30 09:05:02 2018 (r342617) @@ -51,7 +51,8 @@ void HO(void); void end_term(void); #endif -static EFI_INPUT_KEY key_cur; +#define KEYBUFSZ 10 +static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */ static int key_pending; static void efi_cons_probe(struct console *); @@ -438,55 +439,120 @@ efi_cons_putchar(int c) #endif } -int -efi_cons_getchar() +static int +keybuf_getchar(void) { - EFI_INPUT_KEY key; - EFI_STATUS status; - UINTN junk; + int i, c = 0; - if (key_pending) { - key = key_cur; - key_pending = 0; - } else { - /* Try to read a key stroke. We wait for one if none is pending. */ - status = conin->ReadKeyStroke(conin, &key); - while (status == EFI_NOT_READY) { - /* Some EFI implementation (u-boot for example) do not support WaitForKey */ - if (conin->WaitForKey != NULL) - BS->WaitForEvent(1, &conin->WaitForKey, &junk); - status = conin->ReadKeyStroke(conin, &key); + for (i = 0; i < KEYBUFSZ; i++) { + if (keybuf[i] != 0) { + c = keybuf[i]; + keybuf[i] = 0; + break; } } - switch (key.ScanCode) { - case 0x17: /* ESC */ - return (0x1b); /* esc */ + return (c); +} + +static bool +keybuf_ischar(void) +{ + int i; + + for (i = 0; i < KEYBUFSZ; i++) { + if (keybuf[i] != 0) + return (true); } + return (false); +} - /* this can return */ - return (key.UnicodeChar); +/* + * We are not reading input before keybuf is empty, so we are safe + * just to fill keybuf from the beginning. + */ +static void +keybuf_inschar(EFI_INPUT_KEY *key) +{ + + switch (key->ScanCode) { + case 0x1: /* UP */ + keybuf[0] = 0x1b; /* esc */ + keybuf[1] = '['; + keybuf[2] = 'A'; + break; + case 0x2: /* DOWN */ + keybuf[0] = 0x1b; /* esc */ + keybuf[1] = '['; + keybuf[2] = 'B'; + break; + case 0x3: /* RIGHT */ + keybuf[0] = 0x1b; /* esc */ + keybuf[1] = '['; + keybuf[2] = 'C'; + break; + case 0x4: /* LEFT */ + keybuf[0] = 0x1b; /* esc */ + keybuf[1] = '['; + keybuf[2] = 'D'; + break; + case 0x17: + keybuf[0] = 0x1b; /* esc */ + break; + default: + keybuf[0] = key->UnicodeChar; + break; + } } -int -efi_cons_poll() +static bool +efi_readkey(void) { - EFI_INPUT_KEY key; EFI_STATUS status; + EFI_INPUT_KEY key; - if (conin->WaitForKey == NULL) { - if (key_pending) - return (1); - status = conin->ReadKeyStroke(conin, &key); - if (status == EFI_SUCCESS) { - key_cur = key; - key_pending = 1; - } - return (key_pending); + status = conin->ReadKeyStroke(conin, &key); + if (status == EFI_SUCCESS) { + keybuf_inschar(&key); + return (true); } + return (false); +} - /* This can clear the signaled state. */ - return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS); +int +efi_cons_getchar(void) +{ + int c; + + if ((c = keybuf_getchar()) != 0) + return (c); + + key_pending = 0; + + if (efi_readkey()) + return (keybuf_getchar()); + + return (-1); +} + +int +efi_cons_poll(void) +{ + + if (keybuf_ischar() || key_pending) + return (1); + + /* + * Some EFI implementation (u-boot for example) do not support + * WaitForKey(). + * CheckEvent() can clear the signaled state. + */ + if (conin->WaitForKey == NULL) + key_pending = efi_readkey(); + else + key_pending = BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS; + + return (key_pending); } /* Plain direct access to EFI OutputString(). */