From 56758831fe6c5702d3a76a2ea12986a5bf978ef5 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Thu, 5 Sep 2019 22:15:50 +0000 Subject: [PATCH] loader: use teken teminal emulator for x86 and uefi Replace mini cons25 emulator with teken, this does enable us proper console terminal for loader and will make it possible to implement different back end callbacks to draw to screen. At this time we still only "draw" in text mode. --- stand/defs.mk | 7 + stand/efi/include/efilib.h | 1 + stand/efi/libefi/Makefile | 10 +- stand/efi/libefi/efi_console.c | 709 +++++++------- stand/efi/loader/arch/amd64/Makefile.inc | 2 +- stand/efi/loader/arch/i386/Makefile.inc | 2 +- stand/efi/loader/main.c | 6 +- stand/forth/frames.4th | 42 +- stand/i386/libi386/Makefile | 8 +- stand/i386/libi386/vidconsole.c | 1136 +++++++++++++--------- stand/lua/drawer.lua | 24 +- 11 files changed, 1042 insertions(+), 905 deletions(-) diff --git a/stand/defs.mk b/stand/defs.mk index ebf0848b6a1..9b5d7960e41 100644 --- a/stand/defs.mk +++ b/stand/defs.mk @@ -180,6 +180,13 @@ CFLAGS+=-I. all: ${PROG} +CLEANFILES+= teken_state.h +teken.c: teken_state.h + +teken_state.h: ${SYSDIR}/teken/sequences + awk -f ${SYSDIR}/teken/gensequences \ + ${SYSDIR}/teken/sequences > teken_state.h + .if !defined(NO_OBJ) _ILINKS=machine .if ${MACHINE} != ${MACHINE_CPUARCH} && ${MACHINE} != "arm64" diff --git a/stand/efi/include/efilib.h b/stand/efi/include/efilib.h index 44ddb2d4056..e84e54640be 100644 --- a/stand/efi/include/efilib.h +++ b/stand/efi/include/efilib.h @@ -106,6 +106,7 @@ EFI_STATUS errno_to_efi_status(int errno); void efi_time_init(void); void efi_time_fini(void); +bool efi_cons_update_mode(void); EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); EFI_STATUS main(int argc, CHAR16 *argv[]); diff --git a/stand/efi/libefi/Makefile b/stand/efi/libefi/Makefile index 7ca1a1f92fd..40f6f815784 100644 --- a/stand/efi/libefi/Makefile +++ b/stand/efi/libefi/Makefile @@ -22,6 +22,9 @@ SRCS= delay.c \ libefi.c \ wchar.c +.PATH: ${SYSDIR}/teken +SRCS+= teken.c + .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" SRCS+= time.c .elif ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" @@ -45,6 +48,8 @@ CFLAGS+= -fPIC -mno-red-zone .endif CFLAGS+= -I${EFIINC} CFLAGS+= -I${EFIINCMD} +CFLAGS.efi_console.c+= -I${SRCTOP}/sys/teken +CFLAGS.teken.c+= -I${SRCTOP}/sys/teken .if ${MK_LOADER_ZFS} != "no" CFLAGS+= -I${ZFSSRC} CFLAGS+= -DEFI_ZFS_BOOT @@ -56,9 +61,4 @@ CFLAGS+= -I${LDRSRC} # 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 diff --git a/stand/efi/libefi/efi_console.c b/stand/efi/libefi/efi_console.c index a8ed786f786..35f68bcaa31 100644 --- a/stand/efi/libefi/efi_console.c +++ b/stand/efi/libefi/efi_console.c @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include "bootstrap.h" @@ -37,26 +38,57 @@ static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; static SIMPLE_INPUT_INTERFACE *conin; static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *coninex; -#ifdef TERM_EMU -#define DEFAULT_FGCOLOR EFI_LIGHTGRAY -#define DEFAULT_BGCOLOR EFI_BLACK +static tf_bell_t efi_cons_bell; +static tf_cursor_t efi_text_cursor; +static tf_putchar_t efi_text_putchar; +static tf_fill_t efi_text_fill; +static tf_copy_t efi_text_copy; +static tf_param_t efi_text_param; +static tf_respond_t efi_cons_respond; -#define MAXARGS 8 -static int args[MAXARGS], argc; -static int fg_c, bg_c, curx, cury; -static int esc; +static teken_funcs_t tf = { + .tf_bell = efi_cons_bell, + .tf_cursor = efi_text_cursor, + .tf_putchar = efi_text_putchar, + .tf_fill = efi_text_fill, + .tf_copy = efi_text_copy, + .tf_param = efi_text_param, + .tf_respond = efi_cons_respond, +}; -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 +teken_t teken; +teken_pos_t tp; + +struct text_pixel { + teken_char_t c; + teken_attr_t a; +}; + +static struct text_pixel *buffer; #define KEYBUFSZ 10 static unsigned keybuf[KEYBUFSZ]; /* keybuf for extended codes */ static int key_pending; +static const unsigned char teken_color_to_efi_color[16] = { + EFI_BLACK, + EFI_RED, + EFI_GREEN, + EFI_BROWN, + EFI_BLUE, + EFI_MAGENTA, + EFI_CYAN, + EFI_LIGHTGRAY, + EFI_DARKGRAY, + EFI_LIGHTRED, + EFI_LIGHTGREEN, + EFI_YELLOW, + EFI_LIGHTBLUE, + EFI_LIGHTMAGENTA, + EFI_LIGHTCYAN, + EFI_WHITE +}; + static void efi_cons_probe(struct console *); static int efi_cons_init(int); void efi_cons_putchar(int); @@ -75,378 +107,319 @@ struct console efi_console = { efi_cons_poll }; -#ifdef TERM_EMU - -/* Get cursor position. */ -void -get_pos(int *x, int *y) +/* + * Not implemented. + */ +static void +efi_cons_bell(void *s __unused) { - *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) +static void +efi_text_cursor(void *s __unused, const teken_pos_t *p) { - conout->SetCursorPosition(conout, x, y); - if (_x != NULL) - *_x = conout->Mode->CursorColumn; - if (_y != NULL) - *_y = conout->Mode->CursorRow; + UINTN row, col; + + (void) conout->QueryMode(conout, conout->Mode->Mode, &col, &row); + + if (p->tp_col == col) + col = p->tp_col - 1; + else + col = p->tp_col; + + if (p->tp_row == row) + row = p->tp_row - 1; + else + row = p->tp_row; + + conout->SetCursorPosition(conout, col, row); } -/* Clear internal state of the terminal emulation code. */ -void -end_term(void) +static void +efi_text_printchar(const teken_pos_t *p) { - esc = 0; - argc = -1; + UINTN a, attr; + struct text_pixel *px; + teken_color_t fg, bg, tmp; + + px = buffer + p->tp_col + p->tp_row * tp.tp_col; + a = conout->Mode->Attribute; + + fg = teken_256to16(px->a.ta_fgcolor); + bg = teken_256to16(px->a.ta_bgcolor); + if (px->a.ta_format & TF_BOLD) + fg |= TC_LIGHT; + if (px->a.ta_format & TF_BLINK) + bg |= TC_LIGHT; + + if (px->a.ta_format & TF_REVERSE) { + tmp = fg; + fg = bg; + bg = tmp; + } + + attr = EFI_TEXT_ATTR(teken_color_to_efi_color[fg], + teken_color_to_efi_color[bg]); + + conout->SetCursorPosition(conout, p->tp_col, p->tp_row); + + /* to prvent autoscroll, skip print of lower right char */ + if (p->tp_row == tp.tp_row - 1 && + p->tp_col == tp.tp_col - 1) + return; + + (void) conout->SetAttribute(conout, attr); + efi_cons_efiputchar(px->c); + (void) conout->SetAttribute(conout, a); } -#endif +static void +efi_text_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c, + const teken_attr_t *a) +{ + EFI_STATUS status; + int idx; + + idx = p->tp_col + p->tp_row * tp.tp_col; + buffer[idx].c = c; + buffer[idx].a = *a; + efi_text_printchar(p); +} + +static void +efi_text_fill(void *s, const teken_rect_t *r, teken_char_t c, + const teken_attr_t *a) +{ + teken_pos_t p; + UINTN row, col; + + (void) conout->QueryMode(conout, conout->Mode->Mode, &col, &row); + + conout->EnableCursor(conout, FALSE); + for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; + p.tp_row++) + for (p.tp_col = r->tr_begin.tp_col; + p.tp_col < r->tr_end.tp_col; p.tp_col++) + efi_text_putchar(s, &p, c, a); + conout->EnableCursor(conout, TRUE); +} + +static bool +efi_same_pixel(struct text_pixel *px1, struct text_pixel *px2) +{ + if (px1->c != px2->c) + return (false); + + if (px1->a.ta_format != px2->a.ta_format) + return (false); + if (px1->a.ta_fgcolor != px2->a.ta_fgcolor) + return (false); + if (px1->a.ta_bgcolor != px2->a.ta_bgcolor) + return (false); + + return (true); +} + +static void +efi_text_copy(void *ptr __unused, const teken_rect_t *r, const teken_pos_t *p) +{ + int srow, drow; + int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */ + teken_pos_t d, s; + + /* + * Copying is a little tricky. We must make sure we do it in + * correct order, to make sure we don't overwrite our own data. + */ + + nrow = r->tr_end.tp_row - r->tr_begin.tp_row; + ncol = r->tr_end.tp_col - r->tr_begin.tp_col; + + conout->EnableCursor(conout, FALSE); + if (p->tp_row < r->tr_begin.tp_row) { + /* Copy from bottom to top. */ + for (y = 0; y < nrow; y++) { + d.tp_row = p->tp_row + y; + s.tp_row = r->tr_begin.tp_row + y; + drow = d.tp_row * tp.tp_col; + srow = s.tp_row * tp.tp_col; + for (x = 0; x < ncol; x++) { + d.tp_col = p->tp_col + x; + s.tp_col = r->tr_begin.tp_col + x; + + if (!efi_same_pixel( + &buffer[d.tp_col + drow], + &buffer[s.tp_col + srow])) { + buffer[d.tp_col + drow] = + buffer[s.tp_col + srow]; + efi_text_printchar(&d); + } + } + } + } else { + /* Copy from top to bottom. */ + if (p->tp_col < r->tr_begin.tp_col) { + /* Copy from right to left. */ + for (y = nrow - 1; y >= 0; y--) { + d.tp_row = p->tp_row + y; + s.tp_row = r->tr_begin.tp_row + y; + drow = d.tp_row * tp.tp_col; + srow = s.tp_row * tp.tp_col; + for (x = 0; x < ncol; x++) { + d.tp_col = p->tp_col + x; + s.tp_col = r->tr_begin.tp_col + x; + + if (!efi_same_pixel( + &buffer[d.tp_col + drow], + &buffer[s.tp_col + srow])) { + buffer[d.tp_col + drow] = + buffer[s.tp_col + srow]; + efi_text_printchar(&d); + } + } + } + } else { + /* Copy from left to right. */ + for (y = nrow - 1; y >= 0; y--) { + d.tp_row = p->tp_row + y; + s.tp_row = r->tr_begin.tp_row + y; + drow = d.tp_row * tp.tp_col; + srow = s.tp_row * tp.tp_col; + for (x = ncol - 1; x >= 0; x--) { + d.tp_col = p->tp_col + x; + s.tp_col = r->tr_begin.tp_col + x; + + if (!efi_same_pixel( + &buffer[d.tp_col + drow], + &buffer[s.tp_col + srow])) { + buffer[d.tp_col + drow] = + buffer[s.tp_col + srow]; + efi_text_printchar(&d); + } + } + } + } + } + conout->EnableCursor(conout, TRUE); +} + +static void +efi_text_param(void *s __unused, int cmd, unsigned int value) +{ + switch (cmd) { + case TP_SETLOCALCURSOR: + /* + * 0 means normal (usually block), 1 means hidden, and + * 2 means blinking (always block) for compatibility with + * syscons. We don't support any changes except hiding, + * so must map 2 to 0. + */ + value = (value == 1) ? 0 : 1; + /* FALLTHROUGH */ + case TP_SHOWCURSOR: + if (value == 1) + conout->EnableCursor(conout, TRUE); + else + conout->EnableCursor(conout, FALSE); + break; + default: + /* Not yet implemented */ + break; + } +} + +/* + * Not implemented. + */ +static void +efi_cons_respond(void *s __unused, const void *buf __unused, + size_t len __unused) +{ +} static void efi_cons_probe(struct console *cp) { - conout = ST->ConOut; - conin = ST->ConIn; cp->c_flags |= C_PRESENTIN | C_PRESENTOUT; } +bool +efi_cons_update_mode(void) +{ + UINTN cols, rows; + const teken_attr_t *a; + EFI_STATUS status; + char env[8]; + + status = conout->QueryMode(conout, conout->Mode->Mode, &cols, &rows); + if (EFI_ERROR(status)) { + cols = 80; + rows = 24; + } + + 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); + + teken_set_winsize(&teken, &tp); + a = teken_get_defattr(&teken); + + 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; + } + + snprintf(env, sizeof (env), "%u", (unsigned)rows); + setenv("LINES", env, 1); + snprintf(env, sizeof (env), "%u", (unsigned)cols); + setenv("COLUMNS", env, 1); + + return (true); +} + static int efi_cons_init(int arg) { EFI_STATUS status; -#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 + if (conin != NULL) + return (0); + + conout = ST->ConOut; + conin = ST->ConIn; + conout->EnableCursor(conout, TRUE); status = BS->OpenProtocol(ST->ConsoleInHandle, &simple_input_ex_guid, (void **)&coninex, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (status != EFI_SUCCESS) coninex = NULL; - return (0); + + if (efi_cons_update_mode()) + return (0); + + return (1); } -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 - } -} - -#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'; -} - -/* 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 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 -void -HO(void) -{ -} -#endif - void efi_cons_putchar(int c) { -#ifdef TERM_EMU - efi_term_emu(c); -#else - efi_cons_rawputchar(c); -#endif + unsigned char ch = c; + + if (buffer != NULL) + teken_input(&teken, &ch, sizeof (ch)); + else + efi_cons_efiputchar(c); } static int @@ -624,31 +597,13 @@ void efi_cons_efiputchar(int c) { CHAR16 buf[2]; + EFI_STATUS status; - /* - * 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[0] = c; buf[1] = 0; /* terminate string */ + status = conout->TestString(conout, buf); + if (EFI_ERROR(status)) + buf[0] = '?'; conout->OutputString(conout, buf); } diff --git a/stand/efi/loader/arch/amd64/Makefile.inc b/stand/efi/loader/arch/amd64/Makefile.inc index b6d824ce57e..f64adf08ec1 100644 --- a/stand/efi/loader/arch/amd64/Makefile.inc +++ b/stand/efi/loader/arch/amd64/Makefile.inc @@ -11,5 +11,5 @@ SRCS+= nullconsole.c \ comconsole.c \ spinconsole.c -CFLAGS+= -fPIC -DTERM_EMU +CFLAGS+= -fPIC LDFLAGS+= -Wl,-znocombreloc diff --git a/stand/efi/loader/arch/i386/Makefile.inc b/stand/efi/loader/arch/i386/Makefile.inc index 079c73d336a..fcdb6324b2f 100644 --- a/stand/efi/loader/arch/i386/Makefile.inc +++ b/stand/efi/loader/arch/i386/Makefile.inc @@ -9,5 +9,5 @@ SRCS+= nullconsole.c \ comconsole.c \ spinconsole.c -CFLAGS+= -fPIC -DTERM_EMU +CFLAGS+= -fPIC LDFLAGS+= -Wl,-znocombreloc diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index c8311daa488..25b2e7789b7 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -1280,10 +1280,8 @@ command_mode(int argc, char *argv[]) unsigned int mode; int i; char *cp; - char rowenv[8]; EFI_STATUS status; SIMPLE_TEXT_OUTPUT_INTERFACE *conout; - extern void HO(void); conout = ST->ConOut; @@ -1303,9 +1301,7 @@ command_mode(int argc, char *argv[]) printf("couldn't set mode %d\n", mode); return (CMD_ERROR); } - sprintf(rowenv, "%u", (unsigned)rows); - setenv("LINES", rowenv, 1); - HO(); /* set cursor */ + (void) efi_cons_update_mode(); return (CMD_OK); } diff --git a/stand/forth/frames.4th b/stand/forth/frames.4th index b237afe7ac4..ba356cee4ac 100644 --- a/stand/forth/frames.4th +++ b/stand/forth/frames.4th @@ -47,32 +47,32 @@ variable fill 43 constant ascii_plus \ Single frames -196 constant sh_el -179 constant sv_el -218 constant slt_el -192 constant slb_el -191 constant srt_el -217 constant srb_el +0x2500 constant sh_el +0x2502 constant sv_el +0x250c constant slt_el +0x2514 constant slb_el +0x2510 constant srt_el +0x2518 constant srb_el \ Double frames -205 constant dh_el -186 constant dv_el -201 constant dlt_el -200 constant dlb_el -187 constant drt_el -188 constant drb_el +0x2550 constant dh_el +0x2551 constant dv_el +0x2554 constant dlt_el +0x255a constant dlb_el +0x2557 constant drt_el +0x255d constant drb_el \ Fillings 0 constant fill_none 32 constant fill_blank -176 constant fill_dark -177 constant fill_med -178 constant fill_bright +0x2591 constant fill_dark +0x2592 constant fill_med +0x2593 constant fill_bright only forth definitions also frame-drawing : hline ( len x y -- ) \ Draw horizontal single line at-xy \ move cursor 0 do - h_el @ emit + h_el @ xemit loop ; @@ -113,7 +113,7 @@ only forth definitions also frame-drawing 2dup 4 pick 0 do at-xy - v_el @ emit + v_el @ xemit 1+ 2dup loop @@ -129,10 +129,10 @@ only forth definitions also frame-drawing hline \ Draw top horiz line 2dup swap 1+ swap 4 pick + 5 pick 1- -rot hline \ Draw bottom horiz line - 2dup at-xy lt_el @ emit \ Draw left-top corner - 2dup 4 pick + at-xy lb_el @ emit \ Draw left bottom corner - 2dup swap 5 pick + swap at-xy rt_el @ emit \ Draw right top corner - 2 pick + swap 3 pick + swap at-xy rb_el @ emit + 2dup at-xy lt_el @ xemit \ Draw left-top corner + 2dup 4 pick + at-xy lb_el @ xemit \ Draw left bottom corner + 2dup swap 5 pick + swap at-xy rt_el @ xemit \ Draw right top corner + 2 pick + swap 3 pick + swap at-xy rb_el @ xemit 2drop ; diff --git a/stand/i386/libi386/Makefile b/stand/i386/libi386/Makefile index 653d00d3c1b..d6667a548cc 100644 --- a/stand/i386/libi386/Makefile +++ b/stand/i386/libi386/Makefile @@ -14,6 +14,9 @@ SRCS= bio.c biosacpi.c biosdisk.c biosmem.c biospnp.c \ SRCS+= devicename_stubs.c CFLAGS+= -I${ZFSSRC} +.PATH: ${SYSDIR}/teken +SRCS+= teken.c + BOOT_COMCONSOLE_PORT?= 0x3f8 CFLAGS+= -DCOMPORT=${BOOT_COMCONSOLE_PORT} @@ -37,8 +40,9 @@ CFLAGS+= -DSMBIOS_NETWORK_ENDIAN_UUID .endif .endif -# Include simple terminal emulation (cons25-compatible) -CFLAGS+= -DTERM_EMU +# terminal emulation +CFLAGS.vidconsole.c+= -I${SRCTOP}/sys/teken +CFLAGS.teken.c+= -I${SRCTOP}/sys/teken # XXX: make alloca() useable CFLAGS+= -Dalloca=__builtin_alloca diff --git a/stand/i386/libi386/vidconsole.c b/stand/i386/libi386/vidconsole.c index a045cff396f..854a7f16e4c 100644 --- a/stand/i386/libi386/vidconsole.c +++ b/stand/i386/libi386/vidconsole.c @@ -34,11 +34,15 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include +#include + +#include + #include "libi386.h" #if KEYBOARD_PROBE -#include - static int probe_keyboard(void); #endif static void vidc_probe(struct console *cp); @@ -48,41 +52,506 @@ static int vidc_getchar(void); static int vidc_ischar(void); static int vidc_started; +static uint16_t *vgatext; -void get_pos(int *x, int *y); +static tf_bell_t vidc_cons_bell; +static tf_cursor_t vidc_text_cursor; +static tf_putchar_t vidc_text_putchar; +static tf_fill_t vidc_text_fill; +static tf_copy_t vidc_text_copy; +static tf_param_t vidc_text_param; +static tf_respond_t vidc_cons_respond; + +static teken_funcs_t tf = { + .tf_bell = vidc_cons_bell, + .tf_cursor = vidc_text_cursor, + .tf_putchar = vidc_text_putchar, + .tf_fill = vidc_text_fill, + .tf_copy = vidc_text_copy, + .tf_param = vidc_text_param, + .tf_respond = vidc_cons_respond, +}; -#ifdef TERM_EMU -#define MAXARGS 8 -#define DEFAULT_FGCOLOR 7 -#define DEFAULT_BGCOLOR 0 +teken_t teken; +teken_pos_t tp; -void end_term(void); -void bail_out(int c); -void vidc_term_emu(int c); -void curs_move(int *_x, int *_y, int x, int y); -void write_char(int c, int fg, int bg); -void scroll_up(int rows, int fg, int bg); -void CD(void); -void CM(void); -void HO(void); +struct text_pixel { + teken_char_t c; + teken_attr_t a; +}; -static int args[MAXARGS], argc; -static int fg_c, bg_c, curx, cury; -static int esc; -#endif +static struct text_pixel *buffer; +#define NCOLORS 16 + +/* + * Between console's palette and VGA's one: + * - blue and red are swapped (1 <-> 4) + * - yellow and cyan are swapped (3 <-> 6) + */ +static const int cons_to_vga_colors[NCOLORS] = { + 0, 4, 2, 6, 1, 5, 3, 7, + 8, 12, 10, 14, 9, 13, 11, 15 +}; + +#define TEXT_COLS 80 +#define TEXT_ROWS 25 +#define KEYBUFSZ 10 + +static uint8_t keybuf[KEYBUFSZ]; /* keybuf for extended codes */ struct console vidconsole = { - "vidconsole", - "internal video/keyboard", - 0, - vidc_probe, - vidc_init, - vidc_putchar, - vidc_getchar, - vidc_ischar + .c_name = "vidconsole", + .c_desc = "internal video/keyboard", + .c_flags = 0, + .c_probe = vidc_probe, + .c_init = vidc_init, + .c_out = vidc_putchar, + .c_in = vidc_getchar, + .c_ready = vidc_ischar }; +static int +vga_get_reg(int reg, int index) +{ + return (inb(reg + index)); +} + +static int +vga_get_atr(int reg, int i) +{ + int ret; + + (void) inb(reg + VGA_GEN_INPUT_STAT_1); + outb(reg + VGA_AC_WRITE, i); + ret = inb(reg + VGA_AC_READ); + + (void) inb(reg + VGA_GEN_INPUT_STAT_1); + + return (ret); +} + +static void +vga_set_atr(int reg, int i, int v) +{ + (void) inb(reg + VGA_GEN_INPUT_STAT_1); + outb(reg + VGA_AC_WRITE, i); + outb(reg + VGA_AC_WRITE, v); + + (void) inb(reg + VGA_GEN_INPUT_STAT_1); +} + +static void +vga_set_indexed(int reg, int indexreg, int datareg, uint8_t index, uint8_t val) +{ + outb(reg + indexreg, index); + outb(reg + datareg, val); +} + +static int +vga_get_indexed(int reg, int indexreg, int datareg, uint8_t index) +{ + outb(reg + indexreg, index); + return (inb(reg + datareg)); +} + +static int +vga_get_crtc(int reg, int i) +{ + return (vga_get_indexed(reg, VGA_CRTC_ADDRESS, VGA_CRTC_DATA, i)); +} + +static void +vga_set_crtc(int reg, int i, int v) +{ + vga_set_indexed(reg, VGA_CRTC_ADDRESS, VGA_CRTC_DATA, i, v); +} + +static void +vidc_text_set_cursor(teken_unit_t row, teken_unit_t col, bool visible) +{ + uint16_t addr; + uint8_t msl, s, e; + + msl = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_MAX_SCAN_LINE) & 0x1f; + s = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_START) & 0xC0; + e = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_END); + + if (visible == true) { + addr = row * TEXT_COLS + col; + vga_set_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_LOC_HIGH, addr >> 8); + vga_set_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_LOC_LOW, + addr & 0xff); + e = msl; + } else { + s |= (1<<5); + } + vga_set_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_START, s); + vga_set_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_END, e); +} + +static void +vidc_text_get_cursor(teken_unit_t *row, teken_unit_t *col) +{ + uint16_t addr; + + addr = (vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_LOC_HIGH) << 8) + + vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_LOC_LOW); + + *row = addr / TEXT_COLS; + *col = addr % TEXT_COLS; +} + +/* + * Not implemented. + */ +static void +vidc_cons_bell(void *s __unused) +{ +} + +static void +vidc_text_cursor(void *s __unused, const teken_pos_t *p) +{ + teken_unit_t row, col; + + if (p->tp_col == TEXT_COLS) + col = p->tp_col - 1; + else + col = p->tp_col; + + if (p->tp_row == TEXT_ROWS) + row = p->tp_row - 1; + else + row = p->tp_row; + + vidc_text_set_cursor(row, col, true); +} + +/* + * Binary searchable table for Unicode to CP437 conversion. + */ +struct unicp437 { + uint16_t unicode_base; + uint8_t cp437_base; + uint8_t length; +}; + +static const struct unicp437 cp437table[] = { + { 0x0020, 0x20, 0x5e }, { 0x00a0, 0x20, 0x00 }, + { 0x00a1, 0xad, 0x00 }, { 0x00a2, 0x9b, 0x00 }, + { 0x00a3, 0x9c, 0x00 }, { 0x00a5, 0x9d, 0x00 }, + { 0x00a7, 0x15, 0x00 }, { 0x00aa, 0xa6, 0x00 }, + { 0x00ab, 0xae, 0x00 }, { 0x00ac, 0xaa, 0x00 }, + { 0x00b0, 0xf8, 0x00 }, { 0x00b1, 0xf1, 0x00 }, + { 0x00b2, 0xfd, 0x00 }, { 0x00b5, 0xe6, 0x00 }, + { 0x00b6, 0x14, 0x00 }, { 0x00b7, 0xfa, 0x00 }, + { 0x00ba, 0xa7, 0x00 }, { 0x00bb, 0xaf, 0x00 }, + { 0x00bc, 0xac, 0x00 }, { 0x00bd, 0xab, 0x00 }, + { 0x00bf, 0xa8, 0x00 }, { 0x00c4, 0x8e, 0x01 }, + { 0x00c6, 0x92, 0x00 }, { 0x00c7, 0x80, 0x00 }, + { 0x00c9, 0x90, 0x00 }, { 0x00d1, 0xa5, 0x00 }, + { 0x00d6, 0x99, 0x00 }, { 0x00dc, 0x9a, 0x00 }, + { 0x00df, 0xe1, 0x00 }, { 0x00e0, 0x85, 0x00 }, + { 0x00e1, 0xa0, 0x00 }, { 0x00e2, 0x83, 0x00 }, + { 0x00e4, 0x84, 0x00 }, { 0x00e5, 0x86, 0x00 }, + { 0x00e6, 0x91, 0x00 }, { 0x00e7, 0x87, 0x00 }, + { 0x00e8, 0x8a, 0x00 }, { 0x00e9, 0x82, 0x00 }, + { 0x00ea, 0x88, 0x01 }, { 0x00ec, 0x8d, 0x00 }, + { 0x00ed, 0xa1, 0x00 }, { 0x00ee, 0x8c, 0x00 }, + { 0x00ef, 0x8b, 0x00 }, { 0x00f0, 0xeb, 0x00 }, + { 0x00f1, 0xa4, 0x00 }, { 0x00f2, 0x95, 0x00 }, + { 0x00f3, 0xa2, 0x00 }, { 0x00f4, 0x93, 0x00 }, + { 0x00f6, 0x94, 0x00 }, { 0x00f7, 0xf6, 0x00 }, + { 0x00f8, 0xed, 0x00 }, { 0x00f9, 0x97, 0x00 }, + { 0x00fa, 0xa3, 0x00 }, { 0x00fb, 0x96, 0x00 }, + { 0x00fc, 0x81, 0x00 }, { 0x00ff, 0x98, 0x00 }, + { 0x0192, 0x9f, 0x00 }, { 0x0393, 0xe2, 0x00 }, + { 0x0398, 0xe9, 0x00 }, { 0x03a3, 0xe4, 0x00 }, + { 0x03a6, 0xe8, 0x00 }, { 0x03a9, 0xea, 0x00 }, + { 0x03b1, 0xe0, 0x01 }, { 0x03b4, 0xeb, 0x00 }, + { 0x03b5, 0xee, 0x00 }, { 0x03bc, 0xe6, 0x00 }, + { 0x03c0, 0xe3, 0x00 }, { 0x03c3, 0xe5, 0x00 }, + { 0x03c4, 0xe7, 0x00 }, { 0x03c6, 0xed, 0x00 }, + { 0x03d5, 0xed, 0x00 }, { 0x2010, 0x2d, 0x00 }, + { 0x2014, 0x2d, 0x00 }, { 0x2018, 0x60, 0x00 }, + { 0x2019, 0x27, 0x00 }, { 0x201c, 0x22, 0x00 }, + { 0x201d, 0x22, 0x00 }, { 0x2022, 0x07, 0x00 }, + { 0x203c, 0x13, 0x00 }, { 0x207f, 0xfc, 0x00 }, + { 0x20a7, 0x9e, 0x00 }, { 0x20ac, 0xee, 0x00 }, + { 0x2126, 0xea, 0x00 }, { 0x2190, 0x1b, 0x00 }, + { 0x2191, 0x18, 0x00 }, { 0x2192, 0x1a, 0x00 }, + { 0x2193, 0x19, 0x00 }, { 0x2194, 0x1d, 0x00 }, + { 0x2195, 0x12, 0x00 }, { 0x21a8, 0x17, 0x00 }, + { 0x2202, 0xeb, 0x00 }, { 0x2208, 0xee, 0x00 }, + { 0x2211, 0xe4, 0x00 }, { 0x2212, 0x2d, 0x00 }, + { 0x2219, 0xf9, 0x00 }, { 0x221a, 0xfb, 0x00 }, + { 0x221e, 0xec, 0x00 }, { 0x221f, 0x1c, 0x00 }, + { 0x2229, 0xef, 0x00 }, { 0x2248, 0xf7, 0x00 }, + { 0x2261, 0xf0, 0x00 }, { 0x2264, 0xf3, 0x00 }, + { 0x2265, 0xf2, 0x00 }, { 0x2302, 0x7f, 0x00 }, + { 0x2310, 0xa9, 0x00 }, { 0x2320, 0xf4, 0x00 }, + { 0x2321, 0xf5, 0x00 }, { 0x2500, 0xc4, 0x00 }, + { 0x2502, 0xb3, 0x00 }, { 0x250c, 0xda, 0x00 }, + { 0x2510, 0xbf, 0x00 }, { 0x2514, 0xc0, 0x00 }, + { 0x2518, 0xd9, 0x00 }, { 0x251c, 0xc3, 0x00 }, + { 0x2524, 0xb4, 0x00 }, { 0x252c, 0xc2, 0x00 }, + { 0x2534, 0xc1, 0x00 }, { 0x253c, 0xc5, 0x00 }, + { 0x2550, 0xcd, 0x00 }, { 0x2551, 0xba, 0x00 }, + { 0x2552, 0xd5, 0x00 }, { 0x2553, 0xd6, 0x00 }, + { 0x2554, 0xc9, 0x00 }, { 0x2555, 0xb8, 0x00 }, + { 0x2556, 0xb7, 0x00 }, { 0x2557, 0xbb, 0x00 }, + { 0x2558, 0xd4, 0x00 }, { 0x2559, 0xd3, 0x00 }, + { 0x255a, 0xc8, 0x00 }, { 0x255b, 0xbe, 0x00 }, + { 0x255c, 0xbd, 0x00 }, { 0x255d, 0xbc, 0x00 }, + { 0x255e, 0xc6, 0x01 }, { 0x2560, 0xcc, 0x00 }, + { 0x2561, 0xb5, 0x00 }, { 0x2562, 0xb6, 0x00 }, + { 0x2563, 0xb9, 0x00 }, { 0x2564, 0xd1, 0x01 }, + { 0x2566, 0xcb, 0x00 }, { 0x2567, 0xcf, 0x00 }, + { 0x2568, 0xd0, 0x00 }, { 0x2569, 0xca, 0x00 }, + { 0x256a, 0xd8, 0x00 }, { 0x256b, 0xd7, 0x00 }, + { 0x256c, 0xce, 0x00 }, { 0x2580, 0xdf, 0x00 }, + { 0x2584, 0xdc, 0x00 }, { 0x2588, 0xdb, 0x00 }, + { 0x258c, 0xdd, 0x00 }, { 0x2590, 0xde, 0x00 }, + { 0x2591, 0xb0, 0x02 }, { 0x25a0, 0xfe, 0x00 }, + { 0x25ac, 0x16, 0x00 }, { 0x25b2, 0x1e, 0x00 }, + { 0x25ba, 0x10, 0x00 }, { 0x25bc, 0x1f, 0x00 }, + { 0x25c4, 0x11, 0x00 }, { 0x25cb, 0x09, 0x00 }, + { 0x25d8, 0x08, 0x00 }, { 0x25d9, 0x0a, 0x00 }, + { 0x263a, 0x01, 0x01 }, { 0x263c, 0x0f, 0x00 }, + { 0x2640, 0x0c, 0x00 }, { 0x2642, 0x0b, 0x00 }, + { 0x2660, 0x06, 0x00 }, { 0x2663, 0x05, 0x00 }, + { 0x2665, 0x03, 0x01 }, { 0x266a, 0x0d, 0x00 }, + { 0x266c, 0x0e, 0x00 } +}; + +static uint8_t +vga_get_cp437(teken_char_t c) +{ + int min, mid, max; + + min = 0; + max = (sizeof(cp437table) / sizeof(struct unicp437)) - 1; + + if (c < cp437table[0].unicode_base || + c > cp437table[max].unicode_base + cp437table[max].length) + return ('?'); + + while (max >= min) { + mid = (min + max) / 2; + if (c < cp437table[mid].unicode_base) + max = mid - 1; + else if (c > cp437table[mid].unicode_base + + cp437table[mid].length) + min = mid + 1; + else + return (c - cp437table[mid].unicode_base + + cp437table[mid].cp437_base); + } + + return ('?'); +} + +static void +vidc_text_printchar(const teken_pos_t *p) +{ + int i; + uint8_t attr; + struct text_pixel *px; + teken_color_t fg, bg, tmp; + struct cgatext { + uint8_t ch; + uint8_t attr; + } *addr; + + px = buffer + p->tp_col + p->tp_row * tp.tp_col; + fg = teken_256to16(px->a.ta_fgcolor); + bg = teken_256to16(px->a.ta_bgcolor); + if (px->a.ta_format & TF_BOLD) + fg |= TC_LIGHT; + if (px->a.ta_format & TF_BLINK) + bg |= TC_LIGHT; + + if (px->a.ta_format & TF_REVERSE) { + tmp = fg; + fg = bg; + bg = tmp; + } + + attr = (cons_to_vga_colors[bg & 0xf] << 4) | + cons_to_vga_colors[fg & 0xf]; + addr = (struct cgatext *)vgatext + p->tp_col + p->tp_row * tp.tp_col; + addr->ch = vga_get_cp437(px->c); + addr->attr = attr; +} + +static void +vidc_text_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c, + const teken_attr_t *a) +{ + int attr, idx; + + idx = p->tp_col + p->tp_row * tp.tp_col; + buffer[idx].c = c; + buffer[idx].a = *a; + vidc_text_printchar(p); +} + +static void +vidc_text_fill(void *s, const teken_rect_t *r, teken_char_t c, + const teken_attr_t *a) +{ + teken_pos_t p; + teken_unit_t row, col; + + vidc_text_get_cursor(&row, &col); + vidc_text_set_cursor(row, col, false); + for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; + p.tp_row++) + for (p.tp_col = r->tr_begin.tp_col; + p.tp_col < r->tr_end.tp_col; p.tp_col++) + vidc_text_putchar(s, &p, c, a); + vidc_text_set_cursor(row, col, true); +} + +static bool +vidc_same_pixel(struct text_pixel *px1, struct text_pixel *px2) +{ + if (px1->c != px2->c) + return (false); + + if (px1->a.ta_format != px2->a.ta_format) + return (false); + if (px1->a.ta_fgcolor != px2->a.ta_fgcolor) + return (false); + if (px1->a.ta_bgcolor != px2->a.ta_bgcolor) + return (false); + + return (true); +} + +static void +vidc_text_copy(void *ptr __unused, const teken_rect_t *r, const teken_pos_t *p) +{ + int srow, drow; + int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */ + teken_pos_t d, s; + teken_unit_t row, col; + + /* + * Copying is a little tricky. We must make sure we do it in + * correct order, to make sure we don't overwrite our own data. + */ + + nrow = r->tr_end.tp_row - r->tr_begin.tp_row; + ncol = r->tr_end.tp_col - r->tr_begin.tp_col; + + vidc_text_get_cursor(&row, &col); + vidc_text_set_cursor(row, col, false); + if (p->tp_row < r->tr_begin.tp_row) { + /* Copy from bottom to top. */ + for (y = 0; y < nrow; y++) { + d.tp_row = p->tp_row + y; + s.tp_row = r->tr_begin.tp_row + y; + drow = d.tp_row * tp.tp_col; + srow = s.tp_row * tp.tp_col; + for (x = 0; x < ncol; x++) { + d.tp_col = p->tp_col + x; + s.tp_col = r->tr_begin.tp_col + x; + + if (!vidc_same_pixel( + &buffer[d.tp_col + drow], + &buffer[s.tp_col + srow])) { + buffer[d.tp_col + drow] = + buffer[s.tp_col + srow]; + vidc_text_printchar(&d); + } + } + } + } else { + /* Copy from top to bottom. */ + if (p->tp_col < r->tr_begin.tp_col) { + /* Copy from right to left. */ + for (y = nrow - 1; y >= 0; y--) { + d.tp_row = p->tp_row + y; + s.tp_row = r->tr_begin.tp_row + y; + drow = d.tp_row * tp.tp_col; + srow = s.tp_row * tp.tp_col; + for (x = 0; x < ncol; x++) { + d.tp_col = p->tp_col + x; + s.tp_col = r->tr_begin.tp_col + x; + + if (!vidc_same_pixel( + &buffer[d.tp_col + drow], + &buffer[s.tp_col + srow])) { + buffer[d.tp_col + drow] = + buffer[s.tp_col + srow]; + vidc_text_printchar(&d); + } + } + } + } else { + /* Copy from left to right. */ + for (y = nrow - 1; y >= 0; y--) { + d.tp_row = p->tp_row + y; + s.tp_row = r->tr_begin.tp_row + y; + drow = d.tp_row * tp.tp_col; + srow = s.tp_row * tp.tp_col; + for (x = ncol - 1; x >= 0; x--) { + d.tp_col = p->tp_col + x; + s.tp_col = r->tr_begin.tp_col + x; + + if (!vidc_same_pixel( + &buffer[d.tp_col + drow], + &buffer[s.tp_col + srow])) { + buffer[d.tp_col + drow] = + buffer[s.tp_col + srow]; + vidc_text_printchar(&d); + } + } + } + } + } + vidc_text_set_cursor(row, col, true); +} + +static void +vidc_text_param(void *s __unused, int cmd, unsigned int value) +{ + teken_unit_t row, col; + + switch (cmd) { + case TP_SETLOCALCURSOR: + /* + * 0 means normal (usually block), 1 means hidden, and + * 2 means blinking (always block) for compatibility with + * syscons. We don't support any changes except hiding, + * so must map 2 to 0. + */ + value = (value == 1) ? 0 : 1; + /* FALLTHROUGH */ + case TP_SHOWCURSOR: + vidc_text_get_cursor(&row, &col); + if (value == 1) + vidc_text_set_cursor(row, col, true); + else + vidc_text_set_cursor(row, col, false); + break; + default: + /* Not yet implemented */ + break; + } +} + +/* + * Not implemented. + */ +static void +vidc_cons_respond(void *s __unused, const void *buf __unused, + size_t len __unused) +{ +} + static void vidc_probe(struct console *cp) { @@ -103,22 +572,50 @@ vidc_probe(struct console *cp) static int vidc_init(int arg) { - int i; + const teken_attr_t *a; + int val; - if (vidc_started && arg == 0) - return (0); - vidc_started = 1; -#ifdef TERM_EMU - /* Init terminal emulator */ - end_term(); - get_pos(&curx, &cury); - curs_move(&curx, &cury, curx, cury); - fg_c = DEFAULT_FGCOLOR; - bg_c = DEFAULT_BGCOLOR; -#endif - for (i = 0; i < 10 && vidc_ischar(); i++) - (void)vidc_getchar(); - return (0); /* XXX reinit? */ + if (vidc_started && arg == 0) + return (0); + + vidc_started = 1; + + /* + * Check Miscellaneous Output Register (Read at 3CCh, Write at 3C2h) + * for bit 1 (Input/Output Address Select), which means + * color/graphics adapter. + */ + if (vga_get_reg(VGA_REG_BASE, VGA_GEN_MISC_OUTPUT_R) & VGA_GEN_MO_IOA) + vgatext = (uint16_t *)PTOV(VGA_TXT_BASE); + else + vgatext = (uint16_t *)PTOV(VGA_MEM_BASE + VGA_MEM_SIZE); + + /* set 16bit colors */ + val = vga_get_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL); + val &= ~VGA_AC_MC_BI; + val &= ~VGA_AC_MC_ELG; + vga_set_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL, val); + + tp.tp_row = TEXT_ROWS; + tp.tp_col = TEXT_COLS; + buffer = malloc(tp.tp_row * tp.tp_col * sizeof(*buffer)); + if (buffer == NULL) + return (1); + + teken_init(&teken, &tf, NULL); + teken_set_winsize(&teken, &tp); + a = teken_get_defattr(&teken); + + for (int row = 0; row < tp.tp_row; row++) + for (int col = 0; col < tp.tp_col; col++) { + buffer[col + row * tp.tp_col].c = ' '; + buffer[col + row * tp.tp_col].a = *a; + } + + for (int i = 0; i < 10 && vidc_ischar(); i++) + (void) vidc_getchar(); + + return (0); /* XXX reinit? */ } void @@ -132,406 +629,81 @@ vidc_biosputchar(int c) v86int(); } -static void -vidc_rawputchar(int c) -{ - int i; - - if (c == '\t') { - int n; -#ifndef TERM_EMU - int curx, cury; - - get_pos(&curx, %cury); -#endif - - n = 8 - ((curx + 8) % 8); - for (i = 0; i < n; i++) - vidc_rawputchar(' '); - } else { -#ifndef TERM_EMU - vidc_biosputchar(c); -#else - /* Emulate AH=0eh (teletype output) */ - switch(c) { - case '\a': - vidc_biosputchar(c); - return; - case '\r': - curx = 0; - curs_move(&curx, &cury, curx, cury); - return; - case '\n': - cury++; - if (cury > 24) { - scroll_up(1, fg_c, bg_c); - cury--; - } else { - curs_move(&curx, &cury, curx, cury); - } - return; - case '\b': - if (curx > 0) { - curx--; - curs_move(&curx, &cury, curx, cury); - /* write_char(' ', fg_c, bg_c); XXX destructive(!) */ - return; - } - return; - default: - write_char(c, fg_c, bg_c); - curx++; - if (curx > 79) { - curx = 0; - cury++; - } - if (cury > 24) { - curx = 0; - scroll_up(1, fg_c, bg_c); - cury--; - } - } - curs_move(&curx, &cury, curx, cury); -#endif - } -} - -/* Get cursor position on the screen. Result is in edx. Sets - * curx and cury appropriately. - */ -void -get_pos(int *x, int *y) -{ - - v86.ctl = 0; - v86.addr = 0x10; - v86.eax = 0x0300; - v86.ebx = 0x0; - v86int(); - *x = v86.edx & 0x00ff; - *y = (v86.edx & 0xff00) >> 8; -} - -#ifdef TERM_EMU - -/* Move cursor to x rows and y cols (0-based). */ -void -curs_move(int *_x, int *_y, int x, int y) -{ - - v86.ctl = 0; - v86.addr = 0x10; - v86.eax = 0x0200; - v86.ebx = 0x0; - v86.edx = ((0x00ff & y) << 8) + (0x00ff & x); - v86int(); - *_x = x; - *_y = y; - /* If there is ctrl char at this position, cursor would be invisible. - * Make it a space instead. - */ - v86.ctl = 0; - v86.addr = 0x10; - v86.eax = 0x0800; - v86.ebx = 0x0; - v86int(); -#define isvisible(c) (((c) >= 32) && ((c) < 255)) - if (!isvisible(v86.eax & 0x00ff)) { - write_char(' ', fg_c, bg_c); - } -} - -/* Scroll up the whole window by a number of rows. If rows==0, - * clear the window. fg and bg are attributes for the new lines - * inserted in the window. - */ -void -scroll_up(int rows, int fgcol, int bgcol) -{ - - if (rows == 0) - rows = 25; - v86.ctl = 0; - v86.addr = 0x10; - v86.eax = 0x0600 + (0x00ff & rows); - v86.ebx = (bgcol << 12) + (fgcol << 8); - v86.ecx = 0x0; - v86.edx = 0x184f; - v86int(); -} - -/* Write character and attribute at cursor position. */ -void -write_char(int c, int fgcol, int bgcol) -{ - - v86.ctl = 0; - v86.addr = 0x10; - v86.eax = 0x0900 + (0x00ff & c); - v86.ebx = (bgcol << 4) + fgcol; - v86.ecx = 0x1; - v86int(); -} - -/**************************************************************/ -/* - * Screen manipulation functions. They use accumulated data in - * args[] and argc variables. - * - */ - -/* Clear display from current position to end of screen */ -void -CD(void) -{ - - get_pos(&curx, &cury); - if (curx > 0) { - v86.ctl = 0; - v86.addr = 0x10; - v86.eax = 0x0600; - v86.ebx = (bg_c << 4) + fg_c; - v86.ecx = (cury << 8) + curx; - v86.edx = (cury << 8) + 79; - v86int(); - if (++cury > 24) { - end_term(); - return; - } - } - v86.ctl = 0; - v86.addr = 0x10; - v86.eax = 0x0600; - v86.ebx = (bg_c << 4) + fg_c; - v86.ecx = (cury << 8) + 0; - v86.edx = (24 << 8) + 79; - v86int(); - end_term(); -} - -/* Absolute cursor move to args[0] rows and args[1] columns - * (the coordinates are 1-based). - */ -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) */ -void -HO(void) -{ - - argc = 1; - args[0] = args[1] = 1; - CM(); -} - -/* Clear internal state of the terminal emulation code */ -void -end_term(void) -{ - - esc = 0; - argc = -1; -} - -/* Gracefully exit ESC-sequence processing in case of misunderstanding */ -void -bail_out(int c) -{ - char buf[16], *ch; - int i; - - if (esc) { - vidc_rawputchar('\033'); - if (esc != '\033') - vidc_rawputchar(esc); - for (i = 0; i <= argc; ++i) { - sprintf(buf, "%d", args[i]); - ch = buf; - while (*ch) - vidc_rawputchar(*ch++); - } - } - vidc_rawputchar(c); - 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 */ -void -vidc_term_emu(int c) -{ - static int ansi_col[] = { - 0, 4, 2, 6, 1, 5, 3, 7, - }; - int t; - int i; - - switch (esc) { - case 0: - switch (c) { - case '\033': - esc = c; - break; - default: - vidc_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) /* XXX */ - argc = 0; - else if (argc + 1 >= MAXARGS) - bail_out(c); - else - args[++argc] = 0; - break; - case 'H': - if (argc < 0) - HO(); - else if (argc == 1) - CM(); - else - bail_out(c); - break; - case '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; - } - } - end_term(); - break; - default: - if (isdigit(c)) - get_arg(c); - else - bail_out(c); - break; - } - break; - - default: - bail_out(c); - break; - } -} -#endif - static void vidc_putchar(int c) { -#ifdef TERM_EMU - vidc_term_emu(c); -#else - vidc_rawputchar(c); -#endif + unsigned char ch = c; + + if (buffer != NULL) + teken_input(&teken, &ch, sizeof (ch)); + else + vidc_biosputchar(c); } static int vidc_getchar(void) { + int i, c; - if (vidc_ischar()) { - v86.ctl = 0; - v86.addr = 0x16; - v86.eax = 0x0; - v86int(); - return (v86.eax & 0xff); - } else { - return (-1); - } + for (i = 0; i < KEYBUFSZ; i++) { + if (keybuf[i] != 0) { + c = keybuf[i]; + keybuf[i] = 0; + return (c); + } + } + + if (vidc_ischar()) { + v86.ctl = 0; + v86.addr = 0x16; + v86.eax = 0x0; + v86int(); + if ((v86.eax & 0xff) != 0) { + return (v86.eax & 0xff); + } + + /* extended keys */ + switch (v86.eax & 0xff00) { + case 0x4800: /* up */ + keybuf[0] = '['; + keybuf[1] = 'A'; + return (0x1b); /* esc */ + case 0x4b00: /* left */ + keybuf[0] = '['; + keybuf[1] = 'D'; + return (0x1b); /* esc */ + case 0x4d00: /* right */ + keybuf[0] = '['; + keybuf[1] = 'C'; + return (0x1b); /* esc */ + case 0x5000: /* down */ + keybuf[0] = '['; + keybuf[1] = 'B'; + return (0x1b); /* esc */ + default: + return (-1); + } + } else { + return (-1); + } } static int vidc_ischar(void) { + int i; - v86.ctl = V86_FLAGS; - v86.addr = 0x16; - v86.eax = 0x100; - v86int(); - return (!V86_ZR(v86.efl)); + for (i = 0; i < KEYBUFSZ; i++) { + if (keybuf[i] != 0) { + return (1); + } + } + + v86.ctl = V86_FLAGS; + v86.addr = 0x16; + v86.eax = 0x100; + v86int(); + return (!V86_ZR(v86.efl)); } #if KEYBOARD_PROBE @@ -556,13 +728,13 @@ vidc_ischar(void) static void delay7(void) { - /* - * I know this is broken, but no timer is available yet at this stage... - * See also comments in `delay1ms()'. - */ - inb(IO_DUMMY); inb(IO_DUMMY); - inb(IO_DUMMY); inb(IO_DUMMY); - inb(IO_DUMMY); inb(IO_DUMMY); + /* + * I know this is broken, but no timer is available yet at this stage... + * See also comments in `delay1ms()'. + */ + inb(IO_DUMMY); inb(IO_DUMMY); + inb(IO_DUMMY); inb(IO_DUMMY); + inb(IO_DUMMY); inb(IO_DUMMY); } /* @@ -577,9 +749,9 @@ delay7(void) static void delay1ms(void) { - int i = 800; - while (--i >= 0) - (void)inb(0x84); + int i = 800; + while (--i >= 0) + (void) inb(0x84); } /* @@ -593,55 +765,57 @@ delay1ms(void) static int probe_keyboard(void) { - int retry = PROBE_MAXRETRY; - int wait; - int i; + int retry = PROBE_MAXRETRY; + int wait; + int i; - while (--retry >= 0) { - /* flush any noise */ - while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) { - delay7(); - inb(IO_KBD + KBD_DATA_PORT); - delay1ms(); - } + while (--retry >= 0) { + /* flush any noise */ + while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) { + delay7(); + inb(IO_KBD + KBD_DATA_PORT); + delay1ms(); + } + + /* wait until the controller can accept a command */ + for (wait = PROBE_MAXWAIT; wait > 0; --wait) { + if (((i = inb(IO_KBD + KBD_STATUS_PORT)) + & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) + == 0) + break; + if (i & KBDS_ANY_BUFFER_FULL) { + delay7(); + inb(IO_KBD + KBD_DATA_PORT); + } + delay1ms(); + } + if (wait <= 0) + continue; + + /* send the ECHO command */ + outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO); + + /* wait for a response */ + for (wait = PROBE_MAXWAIT; wait > 0; --wait) { + if (inb(IO_KBD + KBD_STATUS_PORT) & + KBDS_ANY_BUFFER_FULL) + break; + delay1ms(); + } + if (wait <= 0) + continue; - /* wait until the controller can accept a command */ - for (wait = PROBE_MAXWAIT; wait > 0; --wait) { - if (((i = inb(IO_KBD + KBD_STATUS_PORT)) - & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0) - break; - if (i & KBDS_ANY_BUFFER_FULL) { delay7(); - inb(IO_KBD + KBD_DATA_PORT); - } - delay1ms(); - } - if (wait <= 0) - continue; - - /* send the ECHO command */ - outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO); - - /* wait for a response */ - for (wait = PROBE_MAXWAIT; wait > 0; --wait) { - if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) - break; - delay1ms(); - } - if (wait <= 0) - continue; - - delay7(); - i = inb(IO_KBD + KBD_DATA_PORT); + i = inb(IO_KBD + KBD_DATA_PORT); #ifdef PROBE_KBD_BEBUG - printf("probe_keyboard: got 0x%x.\n", i); + printf("probe_keyboard: got 0x%x.\n", i); #endif - if (i == KBD_ECHO) { - /* got the right answer */ - return (1); + if (i == KBD_ECHO) { + /* got the right answer */ + return (1); + } } - } - return (0); + return (0); } #endif /* KEYBOARD_PROBE */ diff --git a/stand/lua/drawer.lua b/stand/lua/drawer.lua index ee788919d4a..18030979398 100644 --- a/stand/lua/drawer.lua +++ b/stand/lua/drawer.lua @@ -370,20 +370,20 @@ drawer.frame_styles = { bottom_right = "+", }, ["single"] = { - horizontal = "\xC4", - vertical = "\xB3", - top_left = "\xDA", - bottom_left = "\xC0", - top_right = "\xBF", - bottom_right = "\xD9", + horizontal = "\xE2\x94\x80", + vertical = "\xE2\x94\x82", + top_left = "\xE2\x94\x8C", + bottom_left = "\xE2\x94\x94", + top_right = "\xE2\x94\x90", + bottom_right = "\xE2\x94\x98", }, ["double"] = { - horizontal = "\xCD", - vertical = "\xBA", - top_left = "\xC9", - bottom_left = "\xC8", - top_right = "\xBB", - bottom_right = "\xBC", + horizontal = "\xE2\x95\x90", + vertical = "\xE2\x95\x91", + top_left = "\xE2\x95\x94", + bottom_left = "\xE2\x95\x9A", + top_right = "\xE2\x95\x97", + bottom_right = "\xE2\x95\x9D", }, }