Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 6 Jan 2016 15:38:39 +0000 (UTC)
From:      Ed Maste <emaste@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r293233 - in head/sys/boot: efi/libefi efi/loader ficl/amd64
Message-ID:  <201601061538.u06FcdOe001006@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: emaste
Date: Wed Jan  6 15:38:39 2016
New Revision: 293233
URL: https://svnweb.freebsd.org/changeset/base/293233

Log:
  loader.efi: add terminal emulation support
  
  This is based on the vidconsole implementation.
  
  Submitted by:	Toomas Soome <tsoome@me.com>
  Reviewed by:	adrian
  MFC after:	2 weeks
  Relnotes:	Yes
  Differential Revision:	https://reviews.freebsd.org/D4797

Modified:
  head/sys/boot/efi/libefi/Makefile
  head/sys/boot/efi/libefi/efi_console.c
  head/sys/boot/efi/loader/main.c
  head/sys/boot/ficl/amd64/sysdep.c

Modified: head/sys/boot/efi/libefi/Makefile
==============================================================================
--- head/sys/boot/efi/libefi/Makefile	Wed Jan  6 09:56:06 2016	(r293232)
+++ head/sys/boot/efi/libefi/Makefile	Wed Jan  6 15:38:39 2016	(r293233)
@@ -21,5 +21,6 @@ CFLAGS+= -I${.CURDIR}/../../common
 
 # Handle FreeBSD specific %b and %D printf format specifiers
 CFLAGS+= ${FORMAT_EXTENSIONS}
+CFLAGS+= -DTERM_EMU
 
 .include <bsd.lib.mk>

Modified: head/sys/boot/efi/libefi/efi_console.c
==============================================================================
--- head/sys/boot/efi/libefi/efi_console.c	Wed Jan  6 09:56:06 2016	(r293232)
+++ head/sys/boot/efi/libefi/efi_console.c	Wed Jan  6 15:38:39 2016	(r293233)
@@ -35,6 +35,69 @@ __FBSDID("$FreeBSD$");
 static SIMPLE_TEXT_OUTPUT_INTERFACE	*conout;
 static SIMPLE_INPUT_INTERFACE		*conin;
 
+#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);
+#endif
+
+static void efi_cons_probe(struct console *);
+static int efi_cons_init(int);
+void efi_cons_putchar(int);
+int efi_cons_getchar(void);
+void efi_cons_efiputchar(int);
+int efi_cons_poll(void);
+
+struct console efi_console = {
+	"efi",
+	"EFI console",
+	0,
+	efi_cons_probe,
+	efi_cons_init,
+	efi_cons_putchar,
+	efi_cons_getchar,
+	efi_cons_poll
+};
+
+#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_probe(struct console *cp)
 {
@@ -46,22 +109,314 @@ efi_cons_probe(struct console *cp)
 static int
 efi_cons_init(int arg)
 {
-	conout->SetAttribute(conout, EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_BLACK));
+	conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
+	    DEFAULT_BGCOLOR));
+#ifdef TERM_EMU
+	end_term();
+	get_pos(&curx, &cury);
+	curs_move(&curx, &cury, curx, cury);
+	fg_c = DEFAULT_FGCOLOR;
+	bg_c = DEFAULT_BGCOLOR;
+#endif
+	conout->EnableCursor(conout, TRUE);
 	return 0;
 }
 
+static void
+efi_cons_rawputchar(int c)
+{
+	int i;
+	UINTN x, y;
+	conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
+
+	if (c == '\t')
+		/* XXX lame tab expansion */
+		for (i = 0; i < 8; i++)
+			efi_cons_rawputchar(' ');
+	else {
+#ifndef	TERM_EMU
+		if (c == '\n')
+			efi_cons_efiputchar('\r');
+		else
+			efi_cons_efiputchar(c);
+#else
+		switch (c) {
+		case '\r':
+			curx = 0;
+			curs_move(&curx, &cury, curx, cury);
+			return;
+		case '\n':
+			cury++;
+			if (cury >= y) {
+				efi_cons_efiputchar('\n');
+				cury--;
+			} else
+				curs_move(&curx, &cury, curx, cury);
+			return;
+		case '\b':
+			if (curx > 0) {
+				curx--;
+				curs_move(&curx, &cury, curx, cury);
+			}
+			return;
+		default:
+			efi_cons_efiputchar(c);
+			curx++;
+			if (curx > x-1) {
+				curx = 0;
+				cury++;
+			}
+			if (cury > y-1) {
+				curx = 0;
+				cury--;
+			}
+		}
+		curs_move(&curx, &cury, curx, cury);
+#endif
+	}
+}
+
+/* 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
-efi_cons_putchar(int c)
+HO(void)
 {
-	CHAR16 buf[2];
+	argc = 1;
+	args[0] = args[1] = 1;
+	CM();
+}
 
-	if (c == '\n')
-		efi_cons_putchar('\r');
+/* Clear line from current position to end of line */
+static void
+CL(int direction)
+{
+	int i, len;
+	UINTN x, y;
+	CHAR16 *line;
 
-	buf[0] = c;
-	buf[1] = 0;
+	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;
+	}
 
-	conout->OutputString(conout, buf);
+	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';
+}
+
+/* Emulate basic capabilities of cons25 terminal */
+static void
+efi_term_emu(int c)
+{
+	static int ansi_col[] = {
+		0, 4, 2, 6, 1, 5, 3, 7
+	};
+	int t, i;
+
+	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 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;
+	}
+}
+
+void
+efi_cons_putchar(int c)
+{
+#ifdef TERM_EMU
+	efi_term_emu(c);
+#else
+	efi_cons_rawputchar(c);
+#endif
 }
 
 int
@@ -77,6 +432,12 @@ efi_cons_getchar()
 		BS->WaitForEvent(1, &conin->WaitForKey, &junk);
 		status = conin->ReadKeyStroke(conin, &key);
 	}
+	switch (key.ScanCode) {
+	case 0x17: /* ESC */
+		return (0x1b);  /* esc */
+	}
+
+	/* this can return  */
 	return (key.UnicodeChar);
 }
 
@@ -87,13 +448,36 @@ efi_cons_poll()
 	return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS);
 }
 
-struct console efi_console = {
-	"efi",
-	"EFI console",
-	0,
-	efi_cons_probe,
-	efi_cons_init,
-	efi_cons_putchar,
-	efi_cons_getchar,
-	efi_cons_poll
-};
+/* Plain direct access to EFI OutputString(). */
+void
+efi_cons_efiputchar(int c)
+{
+	CHAR16 buf[2];
+
+	/*
+	 * translate box chars to unicode
+	 */
+	switch (c) {
+	/* single frame */
+	case 0xb3: buf[0] = BOXDRAW_VERTICAL; break;
+	case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break;
+	case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break;
+	case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break;
+	case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break;
+	case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break;
+
+	/* double frame */
+	case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break;
+	case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break;
+	case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break;
+	case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break;
+	case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break;
+	case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break;
+
+	default:
+		buf[0] = c;
+	}
+        buf[1] = 0;     /* terminate string */
+
+	conout->OutputString(conout, buf);
+}

Modified: head/sys/boot/efi/loader/main.c
==============================================================================
--- head/sys/boot/efi/loader/main.c	Wed Jan  6 09:56:06 2016	(r293232)
+++ head/sys/boot/efi/loader/main.c	Wed Jan  6 15:38:39 2016	(r293233)
@@ -334,6 +334,7 @@ command_mode(int argc, char *argv[])
 	char rowenv[8];
 	EFI_STATUS status;
 	SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
+	extern void HO(void);
 
 	conout = ST->ConOut;
 
@@ -355,7 +356,7 @@ command_mode(int argc, char *argv[])
 		}
 		sprintf(rowenv, "%u", (unsigned)rows);
 		setenv("LINES", rowenv, 1);
-
+		HO();		/* set cursor */
 		return (CMD_OK);
 	}
 

Modified: head/sys/boot/ficl/amd64/sysdep.c
==============================================================================
--- head/sys/boot/ficl/amd64/sysdep.c	Wed Jan  6 09:56:06 2016	(r293232)
+++ head/sys/boot/ficl/amd64/sysdep.c	Wed Jan  6 15:38:39 2016	(r293233)
@@ -55,7 +55,7 @@ void  ficlTextOut(FICL_VM *pVM, char *ms
     IGNORE(pVM);
 
     while(*msg != 0)
-	putchar(*(msg++));
+	putchar((unsigned char)*(msg++));
     if (fNewline)
 	putchar('\n');
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201601061538.u06FcdOe001006>