From: Alexander Graf <agraf@suse.de>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v5 16/30] efi_loader: Add console interface
Date: Fri, 4 Mar 2016 01:10:00 +0100 [thread overview]
Message-ID: <1457050214-117592-17-git-send-email-agraf@suse.de> (raw)
In-Reply-To: <1457050214-117592-1-git-send-email-agraf@suse.de>
One of the basic EFI interfaces is the console interface. Using it an EFI
application can interface with the user. This patch implements an EFI console
interface using getc() and putc().
Today, we only implement text based consoles. We also convert the EFI Unicode
characters to UTF-8 on the fly, hoping that everyone managed to jump on the
train by now.
Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Simon Glass <sjg@chromium.org>
---
v1 -> v2:
- Move to GPLv2+
v2 -> v3:
- Add EFIAPI to function prototypes
v3 -> v4:
- return EFI_SUCCESS in efi_cout_enable_cursor()
---
include/efi_loader.h | 5 +
lib/efi_loader/efi_console.c | 360 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 365 insertions(+)
create mode 100644 lib/efi_loader/efi_console.c
diff --git a/include/efi_loader.h b/include/efi_loader.h
index d63fa3a..b4e82ac 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -31,6 +31,11 @@
extern struct efi_system_table systab;
+extern const struct efi_simple_text_output_protocol efi_con_out;
+extern const struct efi_simple_input_interface efi_con_in;
+extern const struct efi_console_control_protocol efi_console_control;
+
+extern const efi_guid_t efi_guid_console_control;
extern const efi_guid_t efi_guid_device_path;
extern const efi_guid_t efi_guid_loaded_image;
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
new file mode 100644
index 0000000..2e0228c
--- /dev/null
+++ b/lib/efi_loader/efi_console.c
@@ -0,0 +1,360 @@
+/*
+ * EFI application console interface
+ *
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+
+/* If we can't determine the console size, default to 80x24 */
+static int console_columns = 80;
+static int console_rows = 24;
+static bool console_size_queried;
+
+const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID;
+
+#define cESC '\x1b'
+#define ESC "\x1b"
+
+static efi_status_t EFIAPI efi_cin_get_mode(
+ struct efi_console_control_protocol *this,
+ int *mode, char *uga_exists, char *std_in_locked)
+{
+ EFI_ENTRY("%p, %p, %p, %p", this, mode, uga_exists, std_in_locked);
+
+ if (mode)
+ *mode = EFI_CONSOLE_MODE_TEXT;
+ if (uga_exists)
+ *uga_exists = 0;
+ if (std_in_locked)
+ *std_in_locked = 0;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cin_set_mode(
+ struct efi_console_control_protocol *this, int mode)
+{
+ EFI_ENTRY("%p, %d", this, mode);
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t EFIAPI efi_cin_lock_std_in(
+ struct efi_console_control_protocol *this,
+ uint16_t *password)
+{
+ EFI_ENTRY("%p, %p", this, password);
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+const struct efi_console_control_protocol efi_console_control = {
+ .get_mode = efi_cin_get_mode,
+ .set_mode = efi_cin_set_mode,
+ .lock_std_in = efi_cin_lock_std_in,
+};
+
+static struct simple_text_output_mode efi_con_mode = {
+ .max_mode = 0,
+ .mode = 0,
+ .attribute = 0,
+ .cursor_column = 0,
+ .cursor_row = 0,
+ .cursor_visible = 1,
+};
+
+static int term_read_reply(int *n, int maxnum, char end_char)
+{
+ char c;
+ int i = 0;
+
+ c = getc();
+ if (c != cESC)
+ return -1;
+ c = getc();
+ if (c != '[')
+ return -1;
+
+ n[0] = 0;
+ while (1) {
+ c = getc();
+ if (c == ';') {
+ i++;
+ if (i >= maxnum)
+ return -1;
+ n[i] = 0;
+ continue;
+ } else if (c == end_char) {
+ break;
+ } else if (c > '9' || c < '0') {
+ return -1;
+ }
+
+ /* Read one more decimal position */
+ n[i] *= 10;
+ n[i] += c - '0';
+ }
+
+ return 0;
+}
+
+static efi_status_t EFIAPI efi_cout_reset(
+ struct efi_simple_text_output_protocol *this,
+ char extended_verification)
+{
+ EFI_ENTRY("%p, %d", this, extended_verification);
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static void print_unicode_in_utf8(u16 c)
+{
+ char utf8[4] = { 0 };
+ char *b = utf8;
+
+ if (c < 0x80) {
+ *(b++) = c;
+ } else if (c < 0x800) {
+ *(b++) = 192 + c / 64;
+ *(b++) = 128 + c % 64;
+ } else {
+ *(b++) = 224 + c / 4096;
+ *(b++) = 128 + c / 64 % 64;
+ *(b++) = 128 + c % 64;
+ }
+
+ puts(utf8);
+}
+
+static efi_status_t EFIAPI efi_cout_output_string(
+ struct efi_simple_text_output_protocol *this,
+ const unsigned short *string)
+{
+ u16 ch;
+
+ EFI_ENTRY("%p, %p", this, string);
+ for (;(ch = *string); string++) {
+ print_unicode_in_utf8(ch);
+ efi_con_mode.cursor_column++;
+ if (ch == '\n') {
+ efi_con_mode.cursor_column = 1;
+ efi_con_mode.cursor_row++;
+ } else if (efi_con_mode.cursor_column > console_columns) {
+ efi_con_mode.cursor_column = 1;
+ efi_con_mode.cursor_row++;
+ }
+ if (efi_con_mode.cursor_row > console_rows) {
+ efi_con_mode.cursor_row = console_rows;
+ }
+ }
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cout_test_string(
+ struct efi_simple_text_output_protocol *this,
+ const unsigned short *string)
+{
+ EFI_ENTRY("%p, %p", this, string);
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cout_query_mode(
+ struct efi_simple_text_output_protocol *this,
+ unsigned long mode_number, unsigned long *columns,
+ unsigned long *rows)
+{
+ EFI_ENTRY("%p, %ld, %p, %p", this, mode_number, columns, rows);
+
+ if (!console_size_queried) {
+ /* Ask the terminal about its size */
+ int n[3];
+ u64 timeout;
+
+ console_size_queried = true;
+
+ /* Empty input buffer */
+ while (tstc())
+ getc();
+
+ printf(ESC"[18t");
+
+ /* Check if we have a terminal that understands */
+ timeout = timer_get_us() + 1000000;
+ while (!tstc())
+ if (timer_get_us() > timeout)
+ goto out;
+
+ /* Read {depth,rows,cols} */
+ if (term_read_reply(n, 3, 't')) {
+ goto out;
+ }
+
+ console_columns = n[2];
+ console_rows = n[1];
+ }
+
+out:
+ if (columns)
+ *columns = console_columns;
+ if (rows)
+ *rows = console_rows;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cout_set_mode(
+ struct efi_simple_text_output_protocol *this,
+ unsigned long mode_number)
+{
+ EFI_ENTRY("%p, %ld", this, mode_number);
+
+ /* We only support text output for now */
+ if (mode_number == EFI_CONSOLE_MODE_TEXT)
+ return EFI_EXIT(EFI_SUCCESS);
+
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t EFIAPI efi_cout_set_attribute(
+ struct efi_simple_text_output_protocol *this,
+ unsigned long attribute)
+{
+ EFI_ENTRY("%p, %lx", this, attribute);
+
+ /* Just ignore attributes (colors) for now */
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t EFIAPI efi_cout_clear_screen(
+ struct efi_simple_text_output_protocol *this)
+{
+ EFI_ENTRY("%p", this);
+
+ printf(ESC"[2J");
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cout_set_cursor_position(
+ struct efi_simple_text_output_protocol *this,
+ unsigned long column, unsigned long row)
+{
+ EFI_ENTRY("%p, %ld, %ld", this, column, row);
+
+ printf(ESC"[%d;%df", (int)row, (int)column);
+ efi_con_mode.cursor_column = column;
+ efi_con_mode.cursor_row = row;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_cout_enable_cursor(
+ struct efi_simple_text_output_protocol *this,
+ bool enable)
+{
+ EFI_ENTRY("%p, %d", this, enable);
+
+ printf(ESC"[?25%c", enable ? 'h' : 'l');
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+const struct efi_simple_text_output_protocol efi_con_out = {
+ .reset = efi_cout_reset,
+ .output_string = efi_cout_output_string,
+ .test_string = efi_cout_test_string,
+ .query_mode = efi_cout_query_mode,
+ .set_mode = efi_cout_set_mode,
+ .set_attribute = efi_cout_set_attribute,
+ .clear_screen = efi_cout_clear_screen,
+ .set_cursor_position = efi_cout_set_cursor_position,
+ .enable_cursor = efi_cout_enable_cursor,
+ .mode = (void*)&efi_con_mode,
+};
+
+static efi_status_t EFIAPI efi_cin_reset(
+ struct efi_simple_input_interface *this,
+ bool extended_verification)
+{
+ EFI_ENTRY("%p, %d", this, extended_verification);
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t EFIAPI efi_cin_read_key_stroke(
+ struct efi_simple_input_interface *this,
+ struct efi_input_key *key)
+{
+ struct efi_input_key pressed_key = {
+ .scan_code = 0,
+ .unicode_char = 0,
+ };
+ char ch;
+
+ EFI_ENTRY("%p, %p", this, key);
+
+ /* We don't do interrupts, so check for timers cooperatively */
+ efi_timer_check();
+
+ if (!tstc()) {
+ /* No key pressed */
+ return EFI_EXIT(EFI_NOT_READY);
+ }
+
+ ch = getc();
+ if (ch == cESC) {
+ /* Escape Sequence */
+ ch = getc();
+ switch (ch) {
+ case cESC: /* ESC */
+ pressed_key.scan_code = 23;
+ break;
+ case 'O': /* F1 - F4 */
+ pressed_key.scan_code = getc() - 'P' + 11;
+ break;
+ case 'a'...'z':
+ ch = ch - 'a';
+ break;
+ case '[':
+ ch = getc();
+ switch (ch) {
+ case 'A'...'D': /* up, down right, left */
+ pressed_key.scan_code = ch - 'A' + 1;
+ break;
+ case 'F': /* End */
+ pressed_key.scan_code = 6;
+ break;
+ case 'H': /* Home */
+ pressed_key.scan_code = 5;
+ break;
+ case '1': /* F5 - F8 */
+ pressed_key.scan_code = getc() - '0' + 11;
+ getc();
+ break;
+ case '2': /* F9 - F12 */
+ pressed_key.scan_code = getc() - '0' + 19;
+ getc();
+ break;
+ case '3': /* DEL */
+ pressed_key.scan_code = 8;
+ getc();
+ break;
+ }
+ break;
+ }
+ } else if (ch == 0x7f) {
+ /* Backspace */
+ ch = 0x08;
+ }
+ pressed_key.unicode_char = ch;
+ *key = pressed_key;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+const struct efi_simple_input_interface efi_con_in = {
+ .reset = efi_cin_reset,
+ .read_key_stroke = efi_cin_read_key_stroke,
+ .wait_for_key = NULL,
+};
--
1.8.5.6
next prev parent reply other threads:[~2016-03-04 0:10 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-04 0:09 [U-Boot] [PATCH v5 00/30] EFI payload / application support Alexander Graf
2016-03-04 0:09 ` [U-Boot] [PATCH v5 01/30] thunderx: Calculate TCR dynamically Alexander Graf
2016-03-17 1:59 ` [U-Boot] [U-Boot,v5,01/30] " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 02/30] arm64: Disable TTBR1 maps in EL1 Alexander Graf
2016-03-17 1:59 ` [U-Boot] [U-Boot,v5,02/30] " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 03/30] arm64: Make full va map code more dynamic Alexander Graf
2016-03-17 1:59 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 04/30] thunderx: Move mmu table into board file Alexander Graf
2016-03-17 2:00 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 05/30] zymqmp: Replace home grown mmu code with generic table approach Alexander Graf
2016-03-17 2:00 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 06/30] tegra: " Alexander Graf
2016-03-17 2:00 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 07/30] vexpress64: Add MMU tables Alexander Graf
2016-03-17 2:00 ` [U-Boot] [U-Boot,v5,07/30] " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 08/30] dwmmc: Increase retry timeout Alexander Graf
2016-03-17 2:00 ` [U-Boot] [U-Boot,v5,08/30] " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 09/30] hikey: Add MMU tables Alexander Graf
2016-03-17 2:00 ` [U-Boot] [U-Boot,v5,09/30] " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 10/30] arm64: Remove non-full-va map code Alexander Graf
2016-03-17 2:00 ` [U-Boot] [U-Boot,v5,10/30] " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 11/30] arm64: Only allow dcache disabled in SPL builds Alexander Graf
2016-03-17 2:01 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 12/30] disk/part.c: Expose list of available block drivers Alexander Graf
2016-03-17 2:01 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 13/30] include/efi_api.h: Add more detailed API definitions Alexander Graf
2016-03-17 2:01 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 14/30] efi_loader: Add PE image loader Alexander Graf
2016-03-17 2:01 ` [U-Boot] [U-Boot,v5,14/30] " Tom Rini
2016-03-04 0:09 ` [U-Boot] [PATCH v5 15/30] efi_loader: Add boot time services Alexander Graf
2016-03-17 2:01 ` [U-Boot] [U-Boot,v5,15/30] " Tom Rini
2016-03-04 0:10 ` Alexander Graf [this message]
2016-03-17 2:01 ` [U-Boot] [U-Boot,v5,16/30] efi_loader: Add console interface Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 17/30] efi_loader: Add runtime services Alexander Graf
2016-03-17 2:01 ` [U-Boot] [U-Boot,v5,17/30] " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 18/30] efi_loader: Add disk interfaces Alexander Graf
2016-03-17 2:01 ` [U-Boot] [U-Boot,v5,18/30] " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 19/30] efi_loader: Add "bootefi" command Alexander Graf
2016-03-09 23:27 ` [U-Boot] [PATCH v6 " Alexander Graf
2016-03-17 2:01 ` [U-Boot] [U-Boot,v6,19/30] " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 20/30] efi_loader: Implement memory allocation and map Alexander Graf
2016-03-17 2:02 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 21/30] arm64: Allow exceptions to return Alexander Graf
2016-03-17 2:02 ` [U-Boot] [U-Boot,v5,21/30] " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 22/30] arm64: Allow EFI payload code to take exceptions Alexander Graf
2016-03-17 2:02 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 23/30] efi_loader: hook up in build environment Alexander Graf
2016-03-17 2:02 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 24/30] efi_loader: Add distro boot script for removable media Alexander Graf
2016-03-09 23:05 ` Alexander Graf
2016-03-09 23:16 ` Tom Rini
2016-03-09 23:26 ` [U-Boot] [PATCH v6 " Alexander Graf
2016-03-17 2:02 ` [U-Boot] [U-Boot, v6, " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 25/30] efi_loader: Add README section in README.efi Alexander Graf
2016-03-17 2:02 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 26/30] efi_loader: Add MAINTAINERS entry Alexander Graf
2016-03-17 2:02 ` [U-Boot] [U-Boot,v5,26/30] " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 27/30] arm64: Replace fdt_name env variables with fdtfile Alexander Graf
2016-03-17 2:02 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 28/30] arm: Allow EFI payload code to take exceptions Alexander Graf
2016-03-17 2:03 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 29/30] efi_loader: Call fdt preparation functions Alexander Graf
2016-03-17 2:03 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 0:10 ` [U-Boot] [PATCH v5 30/30] efi_loader: Pass proper device path in on boot Alexander Graf
2016-03-17 2:03 ` [U-Boot] [U-Boot, v5, " Tom Rini
2016-03-04 9:19 ` [U-Boot] [PATCH] efi_loader: Reserve 2 additional pages for fdt Alexander Graf
2016-03-04 9:41 ` Leif Lindholm
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1457050214-117592-17-git-send-email-agraf@suse.de \
--to=agraf@suse.de \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox