Author: emaste
Date: Wed Jan 20 16:53:38 2016
New Revision: 294445
URL: https://svnweb.freebsd.org/changeset/base/294445

Log:
  MFC r293233: loader.efi: add terminal emulation support
  
  This is based on the vidconsole implementation.
  
  Submitted by: Toomas Soome <tso...@me.com>
  Relnotes:     Yes

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

Modified: stable/10/sys/boot/efi/libefi/Makefile
==============================================================================
--- stable/10/sys/boot/efi/libefi/Makefile      Wed Jan 20 16:45:39 2016        
(r294444)
+++ stable/10/sys/boot/efi/libefi/Makefile      Wed Jan 20 16:53:38 2016        
(r294445)
@@ -19,5 +19,6 @@ CFLAGS+= -I${.CURDIR}/../../common
  
 # Suppress warning from clang for FreeBSD %b and %D formats
 CFLAGS+= -fformat-extensions
+CFLAGS+= -DTERM_EMU
 
 .include <bsd.lib.mk>

Modified: stable/10/sys/boot/efi/libefi/efi_console.c
==============================================================================
--- stable/10/sys/boot/efi/libefi/efi_console.c Wed Jan 20 16:45:39 2016        
(r294444)
+++ stable/10/sys/boot/efi/libefi/efi_console.c Wed Jan 20 16:53:38 2016        
(r294445)
@@ -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: stable/10/sys/boot/efi/loader/main.c
==============================================================================
--- stable/10/sys/boot/efi/loader/main.c        Wed Jan 20 16:45:39 2016        
(r294444)
+++ stable/10/sys/boot/efi/loader/main.c        Wed Jan 20 16:53:38 2016        
(r294445)
@@ -331,6 +331,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;
 
@@ -352,7 +353,7 @@ command_mode(int argc, char *argv[])
                }
                sprintf(rowenv, "%u", (unsigned)rows);
                setenv("LINES", rowenv, 1);
-
+               HO();           /* set cursor */
                return (CMD_OK);
        }
 

Modified: stable/10/sys/boot/ficl/amd64/sysdep.c
==============================================================================
--- stable/10/sys/boot/ficl/amd64/sysdep.c      Wed Jan 20 16:45:39 2016        
(r294444)
+++ stable/10/sys/boot/ficl/amd64/sysdep.c      Wed Jan 20 16:53:38 2016        
(r294445)
@@ -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');
 
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to