Date: Tue, 7 Jul 2015 16:11:43 +1000 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Ian Lepore <ian@freebsd.org> Cc: Neel Natu <neel@freebsd.org>, src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: Re: svn commit: r285217 - head/usr.sbin/bhyve Message-ID: <20150707122407.O1017@besplex.bde.org> In-Reply-To: <1436213492.1334.64.camel@freebsd.org> References: <201507061933.t66JXTtJ050058@repo.freebsd.org> <1436213492.1334.64.camel@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, 6 Jul 2015, Ian Lepore wrote: > On Mon, 2015-07-06 at 19:33 +0000, Neel Natu wrote: >> Author: neel >> Date: Mon Jul 6 19:33:29 2015 >> New Revision: 285217 >> URL: https://svnweb.freebsd.org/changeset/base/285217 >> >> Log: >> Always assert DCD and DSR in bhyve's uart emulation. >> >> The /etc/ttys entry for a serial console in FreeBSD/x86 is as follows: >> ttyu0 "/usr/libexec/getty 3wire" vt100 onifconsole secure >> >> The initial terminal type passed to getty(8) is "3wire" which sets the >> CLOCAL flag. However reset(1) clears this flag and any programs that try >> to open the terminal will hang waiting for DCD to be asserted. >> >> Fix this by always asserting DCD and DSR in the emulated uart. >> >> The following discussion on virtualization@ has more details: >> https://lists.freebsd.org/pipermail/freebsd-virtualization/2015-June/003666.html > > This seems like a wrong fix. A real 3-wire serial console doesn't have > DCD and DSR wired on. Why isn't the right fix here having the user with > this problem to do "stty -f /dev/ttyu0.lock clocal", maybe in rc.local? That is the correct fix. But not in rc.local. rc.d/serial already has support for this, added in 2006. However, rc.d/serial was broken in 2008, in part by removing support for the ioctls used by comcontrol(8) which is used by rc.d/serial. Setting CLOCAL in rc.d/serial doesn't require using comcontrol, but the 3wire entry in rc.d/serial starts with a call to the terminal() function and terminal() uses comcontrol to reset to a default state before making minor adjustments. There is a configuration problem for rc.d/serial. It does nothing by default, since it just has some useful functions and some commented-out examples of some useful configurations. There is no way to pass it parameters to tell it what to do. You have to edit it to configure it. If you actually use rc.d/serial by uncommenting almost anything, then the comcontrol breakage is visible as error messages from comcontrol at boot time. Other breakage is more subtle. E.g., rc.d/serial documents the system default state and resets to it, but the default state was broken in 2008 and rc.d/serial was not broken to match. > Hmmm, or maybe it would be right for getty to do the equivelent when it > sees a 3wire type? That would be another wrong thing, as is the existence of the 3wire type. tty*.lock exists to prevent broken programs like reset(1), getty(8) and cu(1) from breaking the settings, without hard-coding the policy or duplicating configuration details in all programs. It is too hard to fix all such programs. The 3write configuration isn't duplicated, so it only works for getty. The breakage in reset(1) is part of the following mostly-hard-coded settings for c_cflag: % mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL); % mode.c_cflag |= (CS8 | CREAD); % ... % if (tgetflag("EP")) { % mode.c_cflag |= PARENB; % mode.c_cflag &= ~PARODD; % } % if (tgetflag("OP")) { % mode.c_cflag |= PARENB; % mode.c_cflag |= PARODD; % } This clobbers CLOCAL and many other settings. The only ones that can be controlled are PARENB and PARODD. But to control them, you have to set EP and OP in your termcap. All the settings in /etc/gettytab are ignored, except possibly ones for parity if getty somehow arranges to put them in a in termcap and nothing clobbers this. "stty sane" is also quite broken, but not for CLOCAL. It uses a hard-coded default for c_cflag except for CLOCAL: ip->t.c_cflag = TTYDEF_CFLAG | (ip->t.c_cflag & CLOCAL); Most other termios flags and perhaps most control characters do need to be reset by reset(1) and "stty sane", by the definition of resetting. Even CLOCAL might need to be reset, but it is unclear how to control this. TTYDEF_CFLAG is essentially getty's default c_cflag. It is defined in <sys/ttydefaults.h> and is a good default for the initial state (set by drivers) too. Other TTYDEF_*FLAG is also essentially getty's defaults. These are also defined in the <sys/ttydefaults.h>, but are bad for the initial state unless the device is initially (before getty) a console. I fixed this in my drivers in 1993, but the bug is back in most drivers now. rc.d/serial still documents the fixed initial state (all other flags 0). getty(8) is not very broken. It needs to change from the initial state to settings suitable for logins. <sys/ttydefaults.h> gives such settings. The defaults need to be modified in just a few cases. More cases in 1985 than now, since serial ttys were actually often used in 1985, but gettytab is larger now. It has silly old entries like: # Fast dialup terminals, 2400/1200/300 rotary (can start either way) 300 is not too fast, but was not very slow in 1985. ... and silly new entries like: # Entries for 3-wire serial terminals. These don't supply carrier, so # clocal needs to be set, and crtscts needs to be unset. It is painful to have to edit either /etc/ttys or /etc/rc.d/serial to configure the settings, but configuring this in rc.d/serial (or directly in the initial state and lock state devices) has the advantage of working for all programs, while gettytab only works for programs that understand it (just getty(8)?). rc.d/seral also gives more flexibility than gettytab for the 3wire case. The 3wire entries in gettytab are primitive and don't use tc to extend other entries. They enforce no parity, no clocal, and a speed, and accept the default of crtscts being unset by not forcing it to be set. I didn't check the breakage in cu(1), but know that it includes clobbering the device's default speed with a hard coded speed of 9600. The version of cu in Taylor uucp didn't have this bug. ISTR that Taylor had a lot of complications for crtscts that are unnecessary if the system default for crtscts is correct. cu(1) of course doesn't know anything about gettytab, and uses its own config file /etc/remote. So to configure a serial device, the following files need to be edited: - /etc/ttys - termcap files or environment (I set the TERMCAP environment variable in ~/.profile to extend the default of cons25 for other reasons) - /etc/gettytab (if you need a non-default entry) - /etc/remote (if you need a non-default entry. Devices can also be selected in it) - /etc/rc.d/serial (devices must be selected in it. Also change it if you need a non-default entry) It is usually easier not to change all of these. Just use /etc/rc.d/serial or direct sttys on the control devices to fixate a couple of important settings, and depend on defaults for the rest. This is a hack. It depends on normal programs not knowing anything about the lock devices, and on having either correct or suitably broken handling of errors from tcsetattr(). (tcsetattr() is remarkably hard to use. It is supposed to return success iff it set at least 1 attribute successfully, but it can almost always set at least 1 attribute correctly, e.g., by setting an unimportant control character to its previous value. So to determine which attributes were set as requested, the callers should use tcgetattr() after tcsetattr() and check for differences. Changes to individual attributes will fail quite often because the hardware doesn't support the change or the system denies it using the lock state device or otherwise, so callers should be prepared for many differences and only complain about important ones. I haven't seen any programs that do much more than check the return value of tcsetattr(). It would be hard to decide if a large difference like denying a speed or parity change is important.) Some time after 1985, files with default configurations like /etc/gettytab and /etc/remote proved to be far too simple. E.g., communicating with an intelligent modem usually requires a complicated set of commands that is very device-dependent. It is simpler to have this in a script for just one device at a time. Other known bugs involving CLOCAL: - uart used to "fixate" CLOCAL to on for serial consoles, without even making this visible in the initial state or lock state devices, and without allowing this to be controlled by the initial state or lock devices. This gave correct operation, except it didn't allow the controlling CLOCAL in the usual way using the control devices. (Unsetting CLOCAL for a console would usually be foot-shooting, but the sysadmin might know better.) Now, uart doesn't do anything special for CLOCAL, so the other bugs break it. - tty_init_console() doesn't set CLOCAL in the lock state device. So without fixation, bugs like the one in reset(1) break serial consoles. - many console drivers don't even call tty_init_console(). This gives them backwards settings for CLOCAL in the initial state device too. It asks for wronger settings than that, but the default settings are broken by using getty's defaults for non-consoles. - ttydev_open() doesn't honor CLOCAL for callout devices. It ignores the initial state device's setting of CLOCAL and forces CLOCAL on. This usually just breaks later operation of carrier. However, it doesn't even do that if a buggy program like reset(1) accidentally changes CLOCAL back to its correct value. Other known bugs near CLOCAL: - tty_init_console() doesn't clear HUPCL in the initial state device. This is a very large bug. Most of the tty bugs described here are from 2008, but this one is from 2004. - tty_init_console() doesn't set HUPCL in the lock state device - uart still fixates HUPCL for serial consoles. That means ignoring it and acting as if it is off. This works around the 2004 bug above. Before 2004, uart didn't support the initial/lock state devices, so it needed both of the fixation hacks. After 2004, it still needed this one. After 2008, it needed the one for CLOCAL. - sio still fixates HUPCL for serial consoles (in my unbroken version for -current, though not in my development version). Before 2004, it had the only example of correct setting of HUPCL for consoles. But it also fixated HUPCL for consoles, using even uglier code with the same result. Thus it wasn't broken by the 2004 bug, but was always broken by fixation. - uart doesn't honor HUPCL. Combined with fixation, this gives hangup on close never for consoles and always otherwise. I.e., HUPCL is gnored and the condition of not being a console is used to replace the correct condition of HUPCL being set. - tty_init_console() doesn't lock speeds in the lock state device. Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20150707122407.O1017>