Date: Wed, 14 Mar 2018 07:55:30 +0000 (UTC) From: Eitan Adler <eadler@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r330918 - stable/11/sys/dev/syscons Message-ID: <201803140755.w2E7tUKB077717@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: eadler Date: Wed Mar 14 07:55:29 2018 New Revision: 330918 URL: https://svnweb.freebsd.org/changeset/base/330918 Log: MFC r315984: Restore switching to a separate kernel terminal "input" state and extend it to a separate state for each CPU. Terminal "input" is user or kernel output. Its state includes the current parser state for escape sequences and multi-byte characters, and some results of previous parsing (mainly attributes), and in teken the cursor position, but not completed output. This state must be switched for kernel output since the kernel can preempt anything, including itself, and this must not affect the preempted state more than necessary. Since vty0 is shared, it is necessary to affect the frame buffer and cursor position and history, but escape sequences must not be affected and attributes for further output must not be affected. This used to work. The syscons terminal state contained mainly the parser state for escape sequences and attributes, but not the cursor position, and was switched. This was first broken by SMP and/or preemptive kernels. Then there should really be a separate state for each thread, and one more for ddb, or locking to prevent preemption. Serialization of printf() helps. But it is arcane that full syscons escape sequences mostly work in kernel printf(), and I have never seen them used except by me to test this fix. They worked perfectly except for the races, since "input" from the kernel was not special in any way. This was broken to use teken. The general switch was removed, and the kernel normal attribute was switched specially. The kernel reverse attribute (config option SC_CONS_REVERSE_ATTR) became unused, and is still unusable because teken doesn't support default reverse attributes (it used to only be used via the ANSI escape sequence to set reverse video). The only new difficulty for using teken seems to be that the cursor position is in the "input" state, so it must be updated in the active input state for each half of the switch. Do this to complete the restoration. The per-CPU state is mainly to make per-CPU coloring work cleanly, at a cost of some space. Each CPU gets its own full set of attribute (not just the current attribute) maintained in the usual way. This also reduces races from unserialized printf()s. However, this gives races for serialized printf()s that otherwise have none. Nothing prevents the CPU doing the a printf() changing in the middle of an escape sequence. Modified: stable/11/sys/dev/syscons/scterm-teken.c stable/11/sys/dev/syscons/syscons.c stable/11/sys/dev/syscons/syscons.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/dev/syscons/scterm-teken.c ============================================================================== --- stable/11/sys/dev/syscons/scterm-teken.c Wed Mar 14 07:51:33 2018 (r330917) +++ stable/11/sys/dev/syscons/scterm-teken.c Wed Mar 14 07:55:29 2018 (r330918) @@ -164,23 +164,12 @@ scteken_term(scr_stat *scp, void **softc) } static void -scteken_puts(scr_stat *scp, u_char *buf, int len, int kernel) +scteken_puts(scr_stat *scp, u_char *buf, int len) { teken_stat *ts = scp->ts; - teken_attr_t backup, kattr; scp->sc->write_in_progress++; - if (kernel) { - /* Use special colors for kernel messages. */ - backup = *teken_get_curattr(&ts->ts_teken); - scteken_sc_to_te_attr(sc_kattr(), &kattr); - teken_set_curattr(&ts->ts_teken, &kattr); - teken_input(&ts->ts_teken, buf, len); - teken_set_curattr(&ts->ts_teken, &backup); - } else { - /* Print user messages with regular colors. */ - teken_input(&ts->ts_teken, buf, len); - } + teken_input(&ts->ts_teken, buf, len); scp->sc->write_in_progress--; } Modified: stable/11/sys/dev/syscons/syscons.c ============================================================================== --- stable/11/sys/dev/syscons/syscons.c Wed Mar 14 07:51:33 2018 (r330917) +++ stable/11/sys/dev/syscons/syscons.c Wed Mar 14 07:55:29 2018 (r330918) @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include <sys/reboot.h> #include <sys/serial.h> #include <sys/signalvar.h> +#include <sys/smp.h> #include <sys/sysctl.h> #include <sys/tty.h> #include <sys/power.h> @@ -99,6 +100,7 @@ static int sc_console_unit = -1; static int sc_saver_keyb_only = 1; static scr_stat *sc_console; static struct consdev *sc_consptr; +static void *kernel_console_ts[MAXCPU]; static scr_stat main_console; static struct tty *main_devs[MAXCONS]; @@ -183,7 +185,7 @@ static void scshutdown(void *, int); static void scsuspend(void *); static void scresume(void *); static u_int scgetc(sc_softc_t *sc, u_int flags, struct sc_cnstate *sp); -static void sc_puts(scr_stat *scp, u_char *buf, int len, int kernel); +static void sc_puts(scr_stat *scp, u_char *buf, int len); #define SCGETC_CN 1 #define SCGETC_NONBLOCK 2 static void sccnupdate(scr_stat *scp); @@ -220,6 +222,7 @@ static void update_font(scr_stat *); static int save_kbd_state(scr_stat *scp); static int update_kbd_state(scr_stat *scp, int state, int mask); static int update_kbd_leds(scr_stat *scp, int which); +static int sc_kattr(void); static timeout_t blink_screen; static struct tty *sc_alloc_tty(int, int); @@ -397,7 +400,7 @@ sctty_outwakeup(struct tty *tp) if (len == 0) break; SC_VIDEO_LOCK(scp->sc); - sc_puts(scp, buf, len, 0); + sc_puts(scp, buf, len); SC_VIDEO_UNLOCK(scp->sc); } } @@ -544,7 +547,8 @@ sc_attach_unit(int unit, int flags) sc_softc_t *sc; scr_stat *scp; struct cdev *dev; - int vc; + void *oldts, *ts; + int i, vc; if (!vty_enabled(VTY_SC)) return ENXIO; @@ -559,8 +563,27 @@ sc_attach_unit(int unit, int flags) /* assert(sc_console != NULL) */ flags |= SC_KERNEL_CONSOLE; scmeminit(NULL); + + scinit(unit, flags); + + if (sc_console->tsw->te_size > 0) { + /* assert(sc_console->ts != NULL); */ + oldts = sc_console->ts; + for (i = 0; i <= mp_maxid; i++) { + ts = malloc(sc_console->tsw->te_size, M_DEVBUF, M_WAITOK); + bcopy(oldts, ts, sc_console->tsw->te_size); + sc_console->ts = ts; + (*sc_console->tsw->te_default_attr)(sc_console, sc_kattrtab[i], + SC_KERNEL_CONS_REV_ATTR); + kernel_console_ts[i] = ts; + } + sc_console->ts = oldts; + (*sc_console->tsw->te_default_attr)(sc_console, SC_NORM_ATTR, + SC_NORM_REV_ATTR); + } + } else { + scinit(unit, flags); } - scinit(unit, flags); sc = sc_get_softc(unit, flags & SC_KERNEL_CONSOLE); sc->config = flags; @@ -1888,6 +1911,7 @@ sc_cnputc(struct consdev *cd, int c) struct sc_cnstate st; u_char buf[1]; scr_stat *scp = sc_console; + void *oldts, *ts; #ifndef SC_NO_HISTORY #if 0 struct tty *tp; @@ -1951,7 +1975,16 @@ sc_cnputc(struct consdev *cd, int c) if (atomic_load_acq_int(&sc_cnputc_loghead) - sc_cnputc_logtail >= sizeof(sc_cnputc_log)) continue; - sc_puts(scp, buf, 1, 1); + /* Console output has a per-CPU "input" state. Switch for it. */ + oldts = scp->ts; + ts = kernel_console_ts[PCPU_GET(cpuid)]; + if (ts != NULL) { + scp->ts = ts; + (*scp->tsw->te_set_cursor)(scp, scp->xpos, scp->ypos); + } + sc_puts(scp, buf, 1); + scp->ts = oldts; + (*scp->tsw->te_set_cursor)(scp, scp->xpos, scp->ypos); } s = spltty(); /* block sckbdevent and scrn_timer */ @@ -2901,7 +2934,7 @@ exchange_scr(sc_softc_t *sc) } static void -sc_puts(scr_stat *scp, u_char *buf, int len, int kernel) +sc_puts(scr_stat *scp, u_char *buf, int len) { #ifdef DEV_SPLASH /* make screensaver happy */ @@ -2910,7 +2943,7 @@ sc_puts(scr_stat *scp, u_char *buf, int len, int kerne #endif if (scp->tsw) - (*scp->tsw->te_puts)(scp, buf, len, kernel); + (*scp->tsw->te_puts)(scp, buf, len); if (scp->sc->delayed_next_scr) sc_switch_scr(scp->sc, scp->sc->delayed_next_scr - 1); } @@ -3150,7 +3183,8 @@ scinit(int unit, int flags) (void *)sc_buffer, FALSE); if (sc_init_emulator(scp, SC_DFLT_TERM)) sc_init_emulator(scp, "*"); - (*scp->tsw->te_default_attr)(scp, SC_NORM_ATTR, SC_NORM_REV_ATTR); + (*scp->tsw->te_default_attr)(scp, SC_KERNEL_CONS_ATTR, + SC_KERNEL_CONS_REV_ATTR); } else { /* assert(sc_malloc) */ sc->dev = malloc(sizeof(struct tty *)*sc->vtys, M_DEVBUF, @@ -4086,9 +4120,11 @@ sc_bell(scr_stat *scp, int pitch, int duration) } } -int +static int sc_kattr(void) { + if (sc_console == NULL) + return (SC_KERNEL_CONS_ATTR); return (sc_kattrtab[PCPU_GET(cpuid) % nitems(sc_kattrtab)]); } Modified: stable/11/sys/dev/syscons/syscons.h ============================================================================== --- stable/11/sys/dev/syscons/syscons.h Wed Mar 14 07:51:33 2018 (r330917) +++ stable/11/sys/dev/syscons/syscons.h Wed Mar 14 07:55:29 2018 (r330918) @@ -391,7 +391,7 @@ typedef int sc_term_init_t(scr_stat *scp, void **tcp, #define SC_TE_COLD_INIT 0 #define SC_TE_WARM_INIT 1 typedef int sc_term_term_t(scr_stat *scp, void **tcp); -typedef void sc_term_puts_t(scr_stat *scp, u_char *buf, int len, int kernel); +typedef void sc_term_puts_t(scr_stat *scp, u_char *buf, int len); typedef int sc_term_ioctl_t(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data, struct thread *td); typedef int sc_term_reset_t(scr_stat *scp, int code); @@ -593,7 +593,6 @@ void sc_paste(scr_stat *scp, const u_char *p, int cou void sc_respond(scr_stat *scp, const u_char *p, int count, int wakeup); void sc_bell(scr_stat *scp, int pitch, int duration); -int sc_kattr(void); /* schistory.c */ #ifndef SC_NO_HISTORY
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201803140755.w2E7tUKB077717>