NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

port-macppc/52264: kernel crash when Carrier-Detect signal changes on /dev/ttyZ0



>Number:         52264
>Category:       port-macppc
>Synopsis:       kernel crash when Carrier-Detect signal changes on /dev/ttyZ0
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    port-macppc-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue May 30 22:35:00 +0000 2017
>Originator:     Christian Groessler
>Release:        -current from around May-4-2017
>Organization:
>Environment:
	
	
System: NetBSD muc-twinppc 7.99.71 NetBSD 7.99.71 (TWINPPC.MP) #1: Fri May 26 12:31:09 CEST 2017 chris@muc-twinppc:/local/netbsd-src/src/sys/arch/macppc/compile/TWINPPC.MP macppc
Architecture: powerpc
Machine: macppc
>Description:
	When the CD signal changes, I'm getting the following crash:
	http://www.groessler.org/bild/netbsd-macppc-ttyZ0-crash.jpg
	(I just took a photo and didn't type in the values.)

	Matching the addresses with netbsd.map and a disassembly of the kernel indicates that
	the crash happens in the zstty_stsoft() function of sys/dev/ic/z8530tty.c; the call to
	mutex_spin_exit(&tty_lock).
>How-To-Repeat:
	I'm using a special board to convert the built-in modem of my Mac into a serial line.
	When connected to another machine by a null-modem cable, the crash happens when I start
	"kermit" on the other machine and type "set line <xxx>". "xxx" being the serial port
	connected to the Mac on the other machine.

	The problem doesn't happen when "kermit" is already connected to the serial device prior
	to the boot of the macppc machine. But then it happens when I disconnect kermit from
	the serial line.
>Fix:
	This change fixes it for me. I was looking at sys/dev/ic/com.c for "inspiration":

------------
Index: z8530tty.c
===================================================================
RCS file: /net/swamp/zeug/netbsd-rsync/main/src/sys/dev/ic/z8530tty.c,v
retrieving revision 1.131
diff -u -p -r1.131 z8530tty.c
--- z8530tty.c	15 Nov 2014 19:18:18 -0000	1.131
+++ z8530tty.c	26 May 2017 10:30:07 -0000
@@ -547,7 +547,7 @@ zsopen(dev_t dev, int flags, int mode, s
 	struct zstty_softc *zst;
 	struct zs_chanstate *cs;
 	struct tty *tp;
-	int error;
+	int s, error;
 
 	zst = device_lookup_private(&zstty_cd, ZSUNIT(dev));
 	if (zst == NULL)
@@ -563,7 +563,7 @@ zsopen(dev_t dev, int flags, int mode, s
 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
 		return (EBUSY);
 
-	mutex_spin_enter(&tty_lock);
+	s = spltty();
 
 	/*
 	 * Do the following iff this is a first open.
@@ -576,7 +576,7 @@ zsopen(dev_t dev, int flags, int mode, s
 		/* Call the power management hook. */
 		if (cs->enable) {
 			if ((*cs->enable)(cs)) {
-				mutex_spin_exit(&tty_lock);
+				splx(s);
 				printf("%s: device enable failed\n",
 				    device_xname(zst->zst_dev));
 				return (EIO);
@@ -662,7 +662,7 @@ zsopen(dev_t dev, int flags, int mode, s
 		mutex_spin_exit(&cs->cs_lock);
 	}
 
-	mutex_spin_exit(&tty_lock);
+	splx(s);
 
 	error = ttyopen(tp, ZSDIALOUT(dev), ISSET(flags, O_NONBLOCK));
 	if (error)
@@ -894,17 +894,18 @@ zsstart(struct tty *tp)
 	struct zstty_softc *zst;
 	struct zs_chanstate *cs;
 	u_char *tba;
-	int tbc;
+	int s, tbc;
 
 	zst = device_lookup_private(&zstty_cd, ZSUNIT(tp->t_dev));
 	cs = zst->zst_cs;
 
+	s = spltty();
 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
-		return;
+		goto out;
 	if (zst->zst_tx_stopped)
-		return;
+		goto out;
 	if (!ttypull(tp))
-		return;
+		goto out;
 
 	/* Grab the first contiguous region of buffer space. */
 	tba = tp->t_outq.c_cf;
@@ -921,6 +922,7 @@ zsstart(struct tty *tp)
 	if (zst->zst_tbc > 1) {
 		zs_dma_setup(cs, zst->zst_tba, zst->zst_tbc);
 		mutex_spin_exit(&cs->cs_lock);
+		splx(s);
 		return;
 	}
 #endif
@@ -931,6 +933,9 @@ zsstart(struct tty *tp)
 	zst->zst_tba++;
 
 	mutex_spin_exit(&cs->cs_lock);
+out:
+	splx(s);
+	return;
 }
 
 /*
@@ -1665,9 +1670,7 @@ zstty_stsoft(struct zstty_softc *zst, st
 		/*
 		 * Inform the tty layer that carrier detect changed.
 		 */
-		mutex_spin_exit(&tty_lock);
 		(void) (*tp->t_linesw->l_modem)(tp, ISSET(rr0, ZSRR0_DCD));
-		mutex_spin_enter(&tty_lock);
 	}
 
 	if (ISSET(delta, cs->cs_rr0_cts)) {
------------


	There is another driver in sys/dev/ic, cy.c, which uses tty_lock. Don't know if
	it's affected, too. I don't have the hardware to test.



Home | Main Index | Thread Index | Old Index