Subject: port-i386/36578: system may not actually halt if serial console is on a slow device
To: None <port-i386-maintainer@netbsd.org, gnats-admin@netbsd.org,>
From: Greg A. Woods <woods@planix.com>
List: netbsd-bugs
Date: 06/29/2007 19:30:00
>Number:         36578
>Category:       port-i386
>Synopsis:       system may not actually halt if serial console is on a slow device
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    port-i386-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jun 29 19:30:00 +0000 2007
>Originator:     Greg A. Woods
>Release:        netbsd-4
>Organization:
Planix, Inc.; Toronto, Ontario; Canada
>Environment:
	
	
System: NetBSD 4.0BETA2
Architecture: i386
Machine: i386
>Description:

	If the system console is a serial console, and if the device it
	is connected to is using software flow control (XOFF) and that
	device is too slow to accept the ".... Please press any key to
	reoot." message then the system will read the the first XOFF
	character from the UART buffer and reboot instantly instead of
	staying halted as was requested.

>How-To-Repeat:

	See the thread starting here:

		http://mail-index.NetBSD.org/port-i386/2007/06/13/0000.html

	and in particular:

		http://mail-index.NetBSD.org/port-i386/2007/06/29/0003.html

>Fix:

Index: sys/arch/i386/i386/machdep.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.586.2.4
diff -u -r1.586.2.4 machdep.c
--- sys/arch/i386/i386/machdep.c	20 Apr 2007 20:31:25 -0000	1.586.2.4
+++ sys/arch/i386/i386/machdep.c	29 Jun 2007 19:20:14 -0000
@@ -870,6 +870,7 @@
 void
 cpu_reboot(int howto, char *bootstr)
 {
+	int keyval = 0;
 
 	if (cold) {
 		howto |= RB_HALT;
@@ -888,7 +889,7 @@
 			resettodr();
 	}
 
-	/* Disable interrupts. */
+	/* block interrupts. */
 	splhigh();
 
 	/* Do a dump if requested. */
@@ -927,11 +928,10 @@
 	}
 
 	if (howto & RB_HALT) {
-		printf("\n");
-		printf("The operating system has halted.\n");
-		printf("Please press any key to reboot.\n\n");
+		printf("\nThe operating system has halted.\n"
+		       "Please press any key to reboot.\n\n");
 
-#ifdef BEEP_ONHALT
+#ifdef BEEP_ONHALT /* XXX could be:  defined(BEEP_ONHALT_COUNT) && (BEEP_ONHALT_COUNT > 0) */
 		{
 			int c;
 			for (c = BEEP_ONHALT_COUNT; c > 0; c--) {
@@ -944,21 +944,49 @@
 		}
 #endif
 
-		cnpollc(1);	/* for proper keyboard command handling */
-		if (cngetc() == 0) {
-			/* no console attached, so just hlt */
-			for(;;) {
-				__asm volatile("hlt");
+		cnpollc(1);	/* for proper keyboard command handling without
+				 * interrupts */
+		/*
+		 * ACK!!!  The line discipline does _NOT_ get used from within
+		 * the kernel for console I/O (though it probably should be).
+		 *
+		 * If any output above went out too fast for the device
+		 * connected to a serial console then we'll read a <CTRL-S>
+		 * here, and we'll just have to ignore it.
+		 */
+#define ASCII_XOFF	0x13
+		while (keyval != ASCII_XOFF) {
+			if ((keyval = cngetc()) == 0) {
+				/* no console attached, so just hlt */
+				printf("\nCannot read from the console, calling the HLT instruction.\n\n");
+				for (;;) {
+					__asm volatile("hlt");
+				}
+				/*NOTREACHED*/
+			}
+#ifdef DEBUG
+			else if (keyval == ASCII_XOFF) {
+				printf("(ignoring XOFF keypress (DC3, aka 0x%x)\n", keyval);
+				/* XXX even this could trigger another XOFF, sigh... */
 			}
+#endif
 		}
 		cnpollc(0);
 	}
 
+#ifdef DEBUG
+	if (keyval)
+		printf("(read key value 0x%x)\n\n", keyval);
+#endif
 	printf("rebooting...\n");
 	if (cpureset_delay > 0)
 		delay(cpureset_delay * 1000);
 	cpu_reset();
-	for(;;) ;
+	printf("cpu_reset() returned, waiting for hardware to reset...\n\n");
+
+	for (;;) {
+		__asm volatile("hlt");
+	}
 	/*NOTREACHED*/
 }
 

>Unformatted: