Page MenuHomeFreeBSD

D22161.diff
No OneTemporary

D22161.diff

Index: head/stand/efi/include/efilib.h
===================================================================
--- head/stand/efi/include/efilib.h
+++ head/stand/efi/include/efilib.h
@@ -106,6 +106,7 @@
void efi_time_init(void);
void efi_time_fini(void);
+int parse_uefi_con_out(void);
bool efi_cons_update_mode(void);
EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab);
Index: head/stand/efi/libefi/Makefile
===================================================================
--- head/stand/efi/libefi/Makefile
+++ head/stand/efi/libefi/Makefile
@@ -61,4 +61,9 @@
# Handle FreeBSD specific %b and %D printf format specifiers
CFLAGS+= ${FORMAT_EXTENSIONS}
+# Do not use TERM_EMU on arm and arm64 as it doesn't behave well with serial console
+.if ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "aarch64"
+CFLAGS+= -DTERM_EMU
+.endif
+
.include <bsd.lib.mk>
Index: head/stand/efi/libefi/efi_console.c
===================================================================
--- head/stand/efi/libefi/efi_console.c
+++ head/stand/efi/libefi/efi_console.c
@@ -30,6 +30,7 @@
#include <efi.h>
#include <efilib.h>
#include <teken.h>
+#include <sys/reboot.h>
#include "bootstrap.h"
@@ -38,6 +39,26 @@
static SIMPLE_INPUT_INTERFACE *conin;
static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex;
+static int mode; /* Does ConOut have serial console? */
+
+static uint32_t utf8_left;
+static uint32_t utf8_partial;
+#ifdef TERM_EMU
+#define DEFAULT_FGCOLOR EFI_LIGHTGRAY
+#define DEFAULT_BGCOLOR EFI_BLACK
+
+#define MAXARGS 8
+static int args[MAXARGS], argc;
+static int fg_c, bg_c, curx, cury;
+static int esc;
+
+void get_pos(int *x, int *y);
+void curs_move(int *_x, int *_y, int x, int y);
+static void CL(int);
+void HO(void);
+void end_term(void);
+#endif
+
static tf_bell_t efi_cons_bell;
static tf_cursor_t efi_text_cursor;
static tf_putchar_t efi_text_putchar;
@@ -447,6 +468,340 @@
return (CMD_OK);
}
+#ifdef TERM_EMU
+/* Get cursor position. */
+void
+get_pos(int *x, int *y)
+{
+ *x = conout->Mode->CursorColumn;
+ *y = conout->Mode->CursorRow;
+}
+
+/* Move cursor to x rows and y cols (0-based). */
+void
+curs_move(int *_x, int *_y, int x, int y)
+{
+ conout->SetCursorPosition(conout, x, y);
+ if (_x != NULL)
+ *_x = conout->Mode->CursorColumn;
+ if (_y != NULL)
+ *_y = conout->Mode->CursorRow;
+}
+
+/* Clear internal state of the terminal emulation code. */
+void
+end_term(void)
+{
+ esc = 0;
+ argc = -1;
+}
+#endif
+
+static void
+efi_cons_rawputchar(int c)
+{
+ int i;
+ UINTN x, y;
+ conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
+
+ if (c == '\t') {
+ int n;
+
+ n = 8 - ((conout->Mode->CursorColumn + 8) % 8);
+ for (i = 0; i < n; i++)
+ efi_cons_rawputchar(' ');
+ } else {
+#ifndef TERM_EMU
+ if (c == '\n')
+ efi_cons_efiputchar('\r');
+ efi_cons_efiputchar(c);
+#else
+ switch (c) {
+ case '\r':
+ curx = 0;
+ efi_cons_efiputchar('\r');
+ return;
+ case '\n':
+ efi_cons_efiputchar('\n');
+ efi_cons_efiputchar('\r');
+ cury++;
+ if (cury >= y)
+ cury--;
+ curx = 0;
+ return;
+ case '\b':
+ if (curx > 0) {
+ efi_cons_efiputchar('\b');
+ curx--;
+ }
+ return;
+ default:
+ efi_cons_efiputchar(c);
+ curx++;
+ if (curx > x-1) {
+ curx = 0;
+ cury++;
+ }
+ if (cury > y-1) {
+ curx = 0;
+ cury--;
+ }
+ }
+#endif
+ }
+ conout->EnableCursor(conout, TRUE);
+}
+
+#ifdef TERM_EMU
+/* Gracefully exit ESC-sequence processing in case of misunderstanding. */
+static void
+bail_out(int c)
+{
+ char buf[16], *ch;
+ int i;
+
+ if (esc) {
+ efi_cons_rawputchar('\033');
+ if (esc != '\033')
+ efi_cons_rawputchar(esc);
+ for (i = 0; i <= argc; ++i) {
+ sprintf(buf, "%d", args[i]);
+ ch = buf;
+ while (*ch)
+ efi_cons_rawputchar(*ch++);
+ }
+ }
+ efi_cons_rawputchar(c);
+ end_term();
+}
+
+/* Clear display from current position to end of screen. */
+static void
+CD(void)
+{
+ int i;
+ UINTN x, y;
+
+ get_pos(&curx, &cury);
+ if (curx == 0 && cury == 0) {
+ conout->ClearScreen(conout);
+ end_term();
+ return;
+ }
+
+ conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
+ CL(0); /* clear current line from cursor to end */
+ for (i = cury + 1; i < y-1; i++) {
+ curs_move(NULL, NULL, 0, i);
+ CL(0);
+ }
+ curs_move(NULL, NULL, curx, cury);
+ end_term();
+}
+
+/*
+ * Absolute cursor move to args[0] rows and args[1] columns
+ * (the coordinates are 1-based).
+ */
+static void
+CM(void)
+{
+ if (args[0] > 0)
+ args[0]--;
+ if (args[1] > 0)
+ args[1]--;
+ curs_move(&curx, &cury, args[1], args[0]);
+ end_term();
+}
+
+/* Home cursor (left top corner), also called from mode command. */
+void
+HO(void)
+{
+ argc = 1;
+ args[0] = args[1] = 1;
+ CM();
+}
+
+/* Clear line from current position to end of line */
+static void
+CL(int direction)
+{
+ int i, len;
+ UINTN x, y;
+ CHAR16 *line;
+
+ conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
+ switch (direction) {
+ case 0: /* from cursor to end */
+ len = x - curx + 1;
+ break;
+ case 1: /* from beginning to cursor */
+ len = curx;
+ break;
+ case 2: /* entire line */
+ len = x;
+ break;
+ default: /* NOTREACHED */
+ __unreachable();
+ }
+
+ if (cury == y - 1)
+ len--;
+
+ line = malloc(len * sizeof (CHAR16));
+ if (line == NULL) {
+ printf("out of memory\n");
+ return;
+ }
+ for (i = 0; i < len; i++)
+ line[i] = ' ';
+ line[len-1] = 0;
+
+ if (direction != 0)
+ curs_move(NULL, NULL, 0, cury);
+
+ conout->OutputString(conout, line);
+ /* restore cursor position */
+ curs_move(NULL, NULL, curx, cury);
+ free(line);
+ end_term();
+}
+
+static void
+get_arg(int c)
+{
+ if (argc < 0)
+ argc = 0;
+ args[argc] *= 10;
+ args[argc] += c - '0';
+}
+#endif
+
+/* Emulate basic capabilities of cons25 terminal */
+static void
+efi_term_emu(int c)
+{
+#ifdef TERM_EMU
+ static int ansi_col[] = {
+ 0, 4, 2, 6, 1, 5, 3, 7
+ };
+ int t, i;
+ EFI_STATUS status;
+
+ switch (esc) {
+ case 0:
+ switch (c) {
+ case '\033':
+ esc = c;
+ break;
+ default:
+ efi_cons_rawputchar(c);
+ break;
+ }
+ break;
+ case '\033':
+ switch (c) {
+ case '[':
+ esc = c;
+ args[0] = 0;
+ argc = -1;
+ break;
+ default:
+ bail_out(c);
+ break;
+ }
+ break;
+ case '[':
+ switch (c) {
+ case ';':
+ if (argc < 0)
+ argc = 0;
+ else if (argc + 1 >= MAXARGS)
+ bail_out(c);
+ else
+ args[++argc] = 0;
+ break;
+ case 'H': /* ho = \E[H */
+ if (argc < 0)
+ HO();
+ else if (argc == 1)
+ CM();
+ else
+ bail_out(c);
+ break;
+ case 'J': /* cd = \E[J */
+ if (argc < 0)
+ CD();
+ else
+ bail_out(c);
+ break;
+ case 'm':
+ if (argc < 0) {
+ fg_c = DEFAULT_FGCOLOR;
+ bg_c = DEFAULT_BGCOLOR;
+ }
+ for (i = 0; i <= argc; ++i) {
+ switch (args[i]) {
+ case 0: /* back to normal */
+ fg_c = DEFAULT_FGCOLOR;
+ bg_c = DEFAULT_BGCOLOR;
+ break;
+ case 1: /* bold */
+ fg_c |= 0x8;
+ break;
+ case 4: /* underline */
+ case 5: /* blink */
+ bg_c |= 0x8;
+ break;
+ case 7: /* reverse */
+ t = fg_c;
+ fg_c = bg_c;
+ bg_c = t;
+ break;
+ case 22: /* normal intensity */
+ fg_c &= ~0x8;
+ break;
+ case 24: /* not underline */
+ case 25: /* not blinking */
+ bg_c &= ~0x8;
+ break;
+ case 30: case 31: case 32: case 33:
+ case 34: case 35: case 36: case 37:
+ fg_c = ansi_col[args[i] - 30];
+ break;
+ case 39: /* normal */
+ fg_c = DEFAULT_FGCOLOR;
+ break;
+ case 40: case 41: case 42: case 43:
+ case 44: case 45: case 46: case 47:
+ bg_c = ansi_col[args[i] - 40];
+ break;
+ case 49: /* normal */
+ bg_c = DEFAULT_BGCOLOR;
+ break;
+ }
+ }
+ conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c));
+ end_term();
+ break;
+ default:
+ if (isdigit(c))
+ get_arg(c);
+ else
+ bail_out(c);
+ break;
+ }
+ break;
+ default:
+ bail_out(c);
+ break;
+ }
+#else
+ efi_cons_rawputchar(c);
+#endif
+}
+
bool
efi_cons_update_mode(void)
{
@@ -461,35 +816,58 @@
rows = 24;
}
- if (buffer != NULL) {
- if (tp.tp_row == rows && tp.tp_col == cols)
- return (true);
- free(buffer);
- } else {
- teken_init(&teken, &tf, NULL);
- }
+ /*
+ * When we have serial port listed in ConOut, use pre-teken emulator,
+ * if built with.
+ * The problem is, we can not output text on efi and comconsole when
+ * efi also has comconsole bound. But then again, we need to have
+ * terminal emulator for efi text mode to support the menu.
+ * While teken is too expensive to be used on serial console, the
+ * pre-teken emulator is light enough to be used on serial console.
+ */
+ mode = parse_uefi_con_out();
+ if ((mode & RB_SERIAL) == 0) {
+ if (buffer != NULL) {
+ if (tp.tp_row == rows && tp.tp_col == cols)
+ return (true);
+ free(buffer);
+ } else {
+ teken_init(&teken, &tf, NULL);
+ }
- tp.tp_row = rows;
- tp.tp_col = cols;
- buffer = malloc(rows * cols * sizeof(*buffer));
- if (buffer == NULL)
- return (false);
+ tp.tp_row = rows;
+ tp.tp_col = cols;
+ buffer = malloc(rows * cols * sizeof(*buffer));
+ if (buffer == NULL)
+ return (false);
- teken_set_winsize(&teken, &tp);
- a = teken_get_defattr(&teken);
+ teken_set_winsize(&teken, &tp);
+ a = teken_get_defattr(&teken);
- snprintf(env, sizeof(env), "%d", a->ta_fgcolor);
- env_setenv("teken.fg_color", EV_VOLATILE, env, efi_set_colors,
- env_nounset);
- snprintf(env, sizeof(env), "%d", a->ta_bgcolor);
- env_setenv("teken.bg_color", EV_VOLATILE, env, efi_set_colors,
- env_nounset);
+ snprintf(env, sizeof(env), "%d", a->ta_fgcolor);
+ env_setenv("teken.fg_color", EV_VOLATILE, env, efi_set_colors,
+ env_nounset);
+ snprintf(env, sizeof(env), "%d", a->ta_bgcolor);
+ env_setenv("teken.bg_color", EV_VOLATILE, env, efi_set_colors,
+ env_nounset);
- for (int row = 0; row < rows; row++)
- for (int col = 0; col < cols; col++) {
- buffer[col + row * tp.tp_col].c = ' ';
- buffer[col + row * tp.tp_col].a = *a;
+ for (int row = 0; row < rows; row++) {
+ for (int col = 0; col < cols; col++) {
+ buffer[col + row * tp.tp_col].c = ' ';
+ buffer[col + row * tp.tp_col].a = *a;
+ }
}
+ } else {
+#ifdef TERM_EMU
+ conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
+ DEFAULT_BGCOLOR));
+ end_term();
+ get_pos(&curx, &cury);
+ curs_move(&curx, &cury, curx, cury);
+ fg_c = DEFAULT_FGCOLOR;
+ bg_c = DEFAULT_BGCOLOR;
+#endif
+ }
snprintf(env, sizeof (env), "%u", (unsigned)rows);
setenv("LINES", env, 1);
@@ -522,10 +900,108 @@
return (1);
}
+static void
+input_partial(void)
+{
+ unsigned i;
+ uint32_t c;
+
+ if (utf8_left == 0)
+ return;
+
+ for (i = 0; i < sizeof(utf8_partial); i++) {
+ c = (utf8_partial >> (24 - (i << 3))) & 0xff;
+ if (c != 0)
+ efi_term_emu(c);
+ }
+ utf8_left = 0;
+ utf8_partial = 0;
+}
+
+static void
+input_byte(uint8_t c)
+{
+ if ((c & 0x80) == 0x00) {
+ /* One-byte sequence. */
+ input_partial();
+ efi_term_emu(c);
+ return;
+ }
+ if ((c & 0xe0) == 0xc0) {
+ /* Two-byte sequence. */
+ input_partial();
+ utf8_left = 1;
+ utf8_partial = c;
+ return;
+ }
+ if ((c & 0xf0) == 0xe0) {
+ /* Three-byte sequence. */
+ input_partial();
+ utf8_left = 2;
+ utf8_partial = c;
+ return;
+ }
+ if ((c & 0xf8) == 0xf0) {
+ /* Four-byte sequence. */
+ input_partial();
+ utf8_left = 3;
+ utf8_partial = c;
+ return;
+ }
+ if ((c & 0xc0) == 0x80) {
+ /* Invalid state? */
+ if (utf8_left == 0) {
+ efi_term_emu(c);
+ return;
+ }
+ utf8_left--;
+ utf8_partial = (utf8_partial << 8) | c;
+ if (utf8_left == 0) {
+ uint32_t v, u;
+ uint8_t b;
+
+ v = 0;
+ u = utf8_partial;
+ b = (u >> 24) & 0xff;
+ if (b != 0) { /* Four-byte sequence */
+ v = b & 0x07;
+ b = (u >> 16) & 0xff;
+ v = (v << 6) | (b & 0x3f);
+ b = (u >> 8) & 0xff;
+ v = (v << 6) | (b & 0x3f);
+ b = u & 0xff;
+ v = (v << 6) | (b & 0x3f);
+ } else if ((b = (u >> 16) & 0xff) != 0) {
+ v = b & 0x0f; /* Three-byte sequence */
+ b = (u >> 8) & 0xff;
+ v = (v << 6) | (b & 0x3f);
+ b = u & 0xff;
+ v = (v << 6) | (b & 0x3f);
+ } else if ((b = (u >> 8) & 0xff) != 0) {
+ v = b & 0x1f; /* Two-byte sequence */
+ b = u & 0xff;
+ v = (v << 6) | (b & 0x3f);
+ }
+ /* Send unicode char directly to console. */
+ efi_cons_efiputchar(v);
+ utf8_partial = 0;
+ }
+ return;
+ }
+ /* Anything left is illegal in UTF-8 sequence. */
+ input_partial();
+ efi_term_emu(c);
+}
+
void
efi_cons_putchar(int c)
{
unsigned char ch = c;
+
+ if ((mode & RB_SERIAL) != 0) {
+ input_byte(ch);
+ return;
+ }
if (buffer != NULL)
teken_input(&teken, &ch, sizeof (ch));
Index: head/stand/efi/loader/main.c
===================================================================
--- head/stand/efi/loader/main.c
+++ head/stand/efi/loader/main.c
@@ -688,7 +688,7 @@
* ACPI name space to map the UID for the serial port to a port. The
* latter is especially hard.
*/
-static int
+int
parse_uefi_con_out(void)
{
int how, rv;

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 15, 9:44 PM (3 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28757025
Default Alt Text
D22161.diff (12 KB)

Event Timeline