git: 1954e5c1dc58 - main - loader: bring back old text-only video console

From: Warner Losh <imp_at_FreeBSD.org>
Date: Sun, 18 Feb 2024 06:30:32 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=1954e5c1dc583df602e6d7058f59eac71b4be6b2

commit 1954e5c1dc583df602e6d7058f59eac71b4be6b2
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2024-02-18 06:14:44 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-02-18 06:29:07 +0000

    loader: bring back old text-only video console
    
    Bring back vidconsole.c as textvidc.c from 2a0e2c88db20. This console
    does no graphics stuff at all, supports no fancy logos, has known bugs
    in the terminal emulation, etc. However, it is small. It will be a
    build-time option to select between the two. The BIOS loader is running
    out of space when too many options are selected, so this allows people
    to select the smaller one to spend the space elsewhere. This is only the
    verbatim copy of the old vidconsole.c. It's not yet connected to the
    build.
    
    Sponsored by:           Netflix
    Differential Revision:  https://reviews.freebsd.org/D43911
---
 stand/i386/libi386/textvidc.c | 645 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 645 insertions(+)

diff --git a/stand/i386/libi386/textvidc.c b/stand/i386/libi386/textvidc.c
new file mode 100644
index 000000000000..f3ab6f4b98cf
--- /dev/null
+++ b/stand/i386/libi386/textvidc.c
@@ -0,0 +1,645 @@
+/*-
+ * Copyright (c) 1998 Michael Smith (msmith@freebsd.org)
+ * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * 	Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <bootstrap.h>
+#include <btxv86.h>
+#include <machine/psl.h>
+#include "libi386.h"
+
+#if KEYBOARD_PROBE
+#include <machine/cpufunc.h>
+
+static int	probe_keyboard(void);
+#endif
+static void	vidc_probe(struct console *cp);
+static int	vidc_init(int arg);
+static void	vidc_putchar(int c);
+static int	vidc_getchar(void);
+static int	vidc_ischar(void);
+
+static int	vidc_started;
+
+void		get_pos(int *x, int *y);
+
+#ifdef TERM_EMU
+#define MAXARGS		8
+#define DEFAULT_FGCOLOR	7
+#define DEFAULT_BGCOLOR	0
+
+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);
+
+static int	args[MAXARGS], argc;
+static int	fg_c, bg_c, curx, cury;
+static int	esc;
+#endif
+
+
+struct console textvidc = {
+    "vidconsole",
+    "internal video/keyboard",
+    0,
+    vidc_probe,
+    vidc_init,
+    vidc_putchar,
+    vidc_getchar,
+    vidc_ischar
+};
+
+static void
+vidc_probe(struct console *cp)
+{
+    /* look for a keyboard */
+#if KEYBOARD_PROBE
+    if (probe_keyboard())
+#endif
+    {
+	cp->c_flags |= C_PRESENTIN;
+    }
+
+    /* XXX for now, always assume we can do BIOS screen output */
+    cp->c_flags |= C_PRESENTOUT;
+}
+
+static int
+vidc_init(int arg)
+{
+    int		i;
+
+    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? */
+}
+
+static void
+vidc_biosputchar(int c)
+{
+
+    v86.ctl = 0;
+    v86.addr = 0x10;
+    v86.eax = 0xe00 | (c & 0xff);
+    v86.ebx = 0x7;
+    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
+}
+
+static int
+vidc_getchar(void)
+{
+
+    if (vidc_ischar()) {
+	v86.ctl = 0;
+	v86.addr = 0x16;
+	v86.eax = 0x0;
+	v86int();
+	return (v86.eax & 0xff);
+    } else {
+	return (-1);
+    }
+}
+
+static int
+vidc_ischar(void)
+{
+
+    v86.ctl = V86_FLAGS;
+    v86.addr = 0x16;
+    v86.eax = 0x100;
+    v86int();
+    return (!V86_ZR(v86.efl));
+}
+
+#if KEYBOARD_PROBE
+
+#define PROBE_MAXRETRY	5
+#define PROBE_MAXWAIT	400
+#define IO_DUMMY	0x84
+#define IO_KBD		0x060		/* 8042 Keyboard */
+
+/* selected defines from kbdio.h */
+#define KBD_STATUS_PORT 	4	/* status port, read */
+#define KBD_DATA_PORT		0	/* data port, read/write
+					 * also used as keyboard command
+					 * and mouse command port
+					 */
+#define KBDC_ECHO		0x00ee
+#define KBDS_ANY_BUFFER_FULL	0x0001
+#define KBDS_INPUT_BUFFER_FULL	0x0002
+#define KBD_ECHO		0x00ee
+
+/* 7 microsec delay necessary for some keyboard controllers */
+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);
+}
+
+/*
+ * This routine uses an inb to an unused port, the time to execute that
+ * inb is approximately 1.25uS.  This value is pretty constant across
+ * all CPU's and all buses, with the exception of some PCI implentations
+ * that do not forward this I/O address to the ISA bus as they know it
+ * is not a valid ISA bus address, those machines execute this inb in
+ * 60 nS :-(.
+ *
+ */
+static void
+delay1ms(void)
+{
+    int i = 800;
+    while (--i >= 0)
+	(void)inb(0x84);
+}
+
+/*
+ * We use the presence/absence of a keyboard to determine whether the internal
+ * console can be used for input.
+ *
+ * Perform a simple test on the keyboard; issue the ECHO command and see
+ * if the right answer is returned. We don't do anything as drastic as
+ * full keyboard reset; it will be too troublesome and take too much time.
+ */
+static int
+probe_keyboard(void)
+{
+    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();
+	}
+
+	/* 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);
+#ifdef PROBE_KBD_BEBUG
+        printf("probe_keyboard: got 0x%x.\n", i);
+#endif
+	if (i == KBD_ECHO) {
+	    /* got the right answer */
+	    return (1);
+	}
+    }
+
+    return (0);
+}
+#endif /* KEYBOARD_PROBE */