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", }, }