From owner-svn-src-all@freebsd.org Sat Mar 4 08:47:32 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 61825CF8E74; Sat, 4 Mar 2017 08:47:32 +0000 (UTC) (envelope-from bde@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 3C2901389; Sat, 4 Mar 2017 08:47:32 +0000 (UTC) (envelope-from bde@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v248lV5o064745; Sat, 4 Mar 2017 08:47:31 GMT (envelope-from bde@FreeBSD.org) Received: (from bde@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v248lVZS064744; Sat, 4 Mar 2017 08:47:31 GMT (envelope-from bde@FreeBSD.org) Message-Id: <201703040847.v248lVZS064744@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: bde set sender to bde@FreeBSD.org using -f From: Bruce Evans Date: Sat, 4 Mar 2017 08:47:31 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r314646 - head/sys/dev/syscons X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 04 Mar 2017 08:47:32 -0000 Author: bde Date: Sat Mar 4 08:47:31 2017 New Revision: 314646 URL: https://svnweb.freebsd.org/changeset/base/314646 Log: Implement ec_putc() (emergency kernel [syscons] console putc()) and use it in emergency in sc_cnputc(). Locking fixes in sc_cnputc() previously turned off normal output in near-deadlock conditions and added deferred output which might never be completed. Emergency output goes to the frame buffer using sufficiently atomic non-blocking writes if the console is in text mode (in graphics mode, nothing is done, modulo races setting the graphics mode bit). Screen updates overwrite the emergency output if the emergency condition clears enough to reach them. ec_putc() also works for "early" console output in normal x86 text mode as soon as this mode is initialized (if ever). This uses a hard-coded x86 frame buffer address before cninit() and a hopefully MI address after cninit(). But non-x86 is more likely to not support text mode, when ec_putc() will be null. ec_putc() has no dependencies of syscons before cninit(), and only has them later to track syscons' mode changes. This commit doesn't attach ec_putc() for early use. To test emergency use, put a breakpoint in central syscons output code like sc_puts() and do some user output. The system used to race or deadlock in ddb output soon after entry to ddb. The locking fixes deferred the output until after leaving ddb, so ddb was unusable and you had to try typing c[ontinue] blindly until it exited, or better use a serial console in parallel. Now the output goes to a window in the middle 2/3 of the screen. Scrolling is circular and there is no cursor, but otherwise ec_putc() provides full dumb terminal functionality and very fast output that hides artificates from dumb overwrites. Modified: head/sys/dev/syscons/syscons.c Modified: head/sys/dev/syscons/syscons.c ============================================================================== --- head/sys/dev/syscons/syscons.c Sat Mar 4 08:46:57 2017 (r314645) +++ head/sys/dev/syscons/syscons.c Sat Mar 4 08:47:31 2017 (r314646) @@ -266,6 +266,65 @@ static struct cdevsw consolectl_devsw = .d_name = "consolectl", }; +/* ec -- emergency console. */ + +static u_int ec_scroffset; + +/* + * Fake enough of main_console for ec_putc() to work very early on x86 if + * the kernel starts in normal color text mode. On non-x86, scribbling + * to the x86 normal color text frame buffer's addresses is unsafe, so + * set (likely non-fake) graphics mode to get a null initial ec_putc(). + */ +static scr_stat fake_main_console = { + .scr.vtb_buffer = 0xb8000, + .xsize = 80, + .ysize = 25, +#if !defined(__amd64__) && !defined(__i386__) + .status = GRAPHICS_MODE, +#endif +}; + +#define main_console (sc_console == NULL ? fake_main_console : main_console) + +static void +ec_putc(int c) +{ + u_short *scrptr; + u_int ind; + int attr, column, mysize, width, xsize, yborder, ysize; + + if (main_console.status & GRAPHICS_MODE || + c < 0 || c > 0xff || c == '\a') + return; + xsize = main_console.xsize; + ysize = main_console.ysize; + yborder = ysize / 5; + scrptr = (u_short *)main_console.scr.vtb_buffer + xsize * yborder; + mysize = xsize * (ysize - 2 * yborder); + do { + ind = ec_scroffset; + column = ind % xsize; + width = (c == '\b' ? -1 : c == '\t' ? (column + 8) & ~7 : + c == '\r' ? -column : c == '\n' ? xsize - column : 1); + if (width == 0 || (width < 0 && ind < -width)) + return; + } while (atomic_cmpset_rel_int(&ec_scroffset, ind, ind + width) == 0); + if (c == '\b' || c == '\r') + return; + if (c == '\n') + ind += xsize; /* XXX clearing from new pos is not atomic */ + + attr = sc_kattr(); + if (c == '\t' || c == '\n') + c = ' '; + do + scrptr[ind++ % mysize] = (attr << 8) | c; + while (--width != 0); +} + +#undef main_console + int sc_probe_unit(int unit, int flags) { @@ -1861,10 +1920,13 @@ sc_cnputc(struct consdev *cd, int c) sc_cnputc_log[head % sizeof(sc_cnputc_log)] = c; /* - * If we couldn't open, return to defer output. + * If we couldn't open, do special reentrant output and return to defer + * normal output. */ - if (!st.scr_opened) + if (!st.scr_opened) { + ec_putc(c); return; + } #ifndef SC_NO_HISTORY if (scp == scp->sc->cur_scp && scp->status & SLKED) {