boot2/loader: serial port handling

Xin Li delphij at delphij.net
Fri Oct 12 23:30:26 UTC 2012


Hi,

We have some rather hacky quick hack at $WORK that addresses a problem
we have found with boot2/loader and wants to share it and see if we can
have more neat solution.

Here is the problem: the current boot2 and loader have various places
where it considers serial port to exist.  When the port is not there,
the code would hang because it tests whether the hardware's -READY bit,
basically something like:

	do {
	} while (inpb(state register) & READY_BIT);

This unfortunately would enter an infinite loop when the device is not
present -- all in operations would get all bits set.

To reproduce this, one can compile boot2/loader with non-existent port
and the system will hang at very early stage of boot.

---

Because boot2 is size constrained we can not use very sophisticated
detection logic there, what I did is to use something like:

	outb(line control register, word)
	if (inb(line control register) != word)
		Disable the serial port read/write

For loader I'm not sure if we should use better detection logic.  By the
way, it seems that the system may force using the default console in
loader regardless if the detection logic said no, if it decides that's
the only usable one.

So what would be the right way to solve these issue?

Cheers,
-- 
Xin LI <delphij at delphij.net>    https://www.delphij.net/
FreeBSD - The Power to Serve!           Live free or die
-------------- next part --------------
Index: sys/boot/i386/boot2/boot2.c
===================================================================
--- sys/boot/i386/boot2/boot2.c	(revision 241434)
+++ sys/boot/i386/boot2/boot2.c	(working copy)
@@ -415,8 +415,10 @@ parse()
 	    }
 	    ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
 		     OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
-	    if (ioctrl & IO_SERIAL)
-	        sio_init(115200 / comspeed);
+	    if (ioctrl & IO_SERIAL) {
+		if (sio_init(115200 / comspeed))
+			ioctrl &= ~IO_SERIAL;
+	    }
 	} else {
 	    for (q = arg--; *q && *q != '('; q++);
 	    if (*q) {
Index: sys/boot/i386/boot2/lib.h
===================================================================
--- sys/boot/i386/boot2/lib.h	(revision 241434)
+++ sys/boot/i386/boot2/lib.h	(working copy)
@@ -17,7 +17,7 @@
  * $FreeBSD$
  */
 
-void sio_init(int) __attribute__((regparm (3)));
+int sio_init(int) __attribute__((regparm (3)));
 void sio_flush(void);
 void sio_putc(int) __attribute__((regparm (3)));
 int sio_getc(void);
Index: sys/boot/i386/boot2/sio.S
===================================================================
--- sys/boot/i386/boot2/sio.S	(revision 241434)
+++ sys/boot/i386/boot2/sio.S	(working copy)
@@ -24,12 +24,15 @@
 		.globl sio_getc
 		.globl sio_ischar
 
-/* void sio_init(int div) */
+/* int sio_init(int div) */
 
 sio_init:	pushl %eax
 		movw $SIO_PRT+0x3,%dx		# Data format reg
 		movb $SIO_FMT|0x80,%al		# Set format
 		outb %al,(%dx)			#  and DLAB
+		inb (%dx),%al
+		cmpb $SIO_FMT|0x80,%al
+		jnz sio_init.1
 		subb $0x3,%dl			# Divisor latch reg
 		popl %eax
 		outw %ax,(%dx)			#  BPS
@@ -41,8 +44,13 @@ sio_init:	pushl %eax
 		outb %al,(%dx)			#  DTR
 		incl %edx			# Line status reg
 		call sio_flush
+		xor %eax,%eax
 		ret
+sio_init.1:	popl %eax
+		movb $0x1,%al
+		ret
 
+
 /* void sio_flush(void) */
 
 sio_flush.0:	call sio_getc.1 		# Get character
Index: sys/boot/i386/libi386/comconsole.c
===================================================================
--- sys/boot/i386/libi386/comconsole.c	(revision 241434)
+++ sys/boot/i386/libi386/comconsole.c	(working copy)
@@ -33,7 +33,7 @@ __FBSDID("$FreeBSD$");
 #include "libi386.h"
 
 #define COMC_FMT	0x3		/* 8N1 */
-#define COMC_TXWAIT	0x40000		/* transmit timeout */
+#define COMC_TXWAIT	0x80		/* transmit timeout */
 #define COMC_BPS(x)	(115200 / (x))	/* speed to DLAB divisor */
 #define COMC_DIV2BPS(x)	(115200 / (x))	/* DLAB divisor to speed */
 
@@ -57,6 +57,7 @@ static int	comc_speed_set(struct env_var *ev, int
 
 static int	comc_started;
 static int	comc_curspeed;
+static int	comc_disabled;
 
 struct console comconsole = {
     "comconsole",
@@ -76,9 +77,12 @@ comc_probe(struct console *cp)
     char *cons, *speedenv;
     int speed;
 
-    /* XXX check the BIOS equipment list? */
-    cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
+    u_char	dlbh;
+    u_char	dlbl;
+    u_char	cfcr;
 
+    comc_disabled = 0;
+
     if (comc_curspeed == 0) {
 	comc_curspeed = COMSPEED;
 	/*
@@ -102,6 +106,22 @@ comc_probe(struct console *cp)
 	env_setenv("comconsole_speed", EV_VOLATILE, speedbuf, comc_speed_set,
 	    env_nounset);
     }
+
+    cfcr = inb(COMPORT + com_cfcr);
+    outb(COMPORT + com_cfcr, CFCR_DLAB | cfcr);
+
+    dlbl = inb(COMPORT + com_dlbl);
+    dlbh = inb(COMPORT + com_dlbh);
+
+    outb(COMPORT + com_cfcr, cfcr);
+
+    if (dlbl == 0xff && dlbh == 0xff && cfcr == 0xff) {
+	cp->c_flags &= ~(C_PRESENTIN | C_PRESENTOUT);
+	comc_disabled = 1;
+	return;
+    }
+
+    cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT);
 }
 
 static int
@@ -121,6 +141,9 @@ comc_putchar(int c)
 {
     int wait;
 
+    if (comc_disabled)
+        return;
+
     for (wait = COMC_TXWAIT; wait > 0; wait--)
         if (inb(COMPORT + com_lsr) & LSR_TXRDY) {
 	    outb(COMPORT + com_data, (u_char)c);
@@ -131,6 +154,10 @@ comc_putchar(int c)
 static int
 comc_getchar(void)
 {
+
+    if (comc_disabled)
+        return -1;
+
     return(comc_ischar() ? inb(COMPORT + com_data) : -1);
 }
 
@@ -161,6 +188,7 @@ comc_speed_set(struct env_var *ev, int flags, cons
 static void
 comc_setup(int speed)
 {
+    int retry = 0x80;
 
     comc_curspeed = speed;
 
@@ -172,7 +200,7 @@ comc_setup(int speed)
 
     do
         inb(COMPORT + com_data);
-    while (inb(COMPORT + com_lsr) & LSR_RXRDY);
+    while (inb(COMPORT + com_lsr) & LSR_RXRDY && (--retry > 0));
 }
 
 static int
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 455 bytes
Desc: OpenPGP digital signature
URL: <http://lists.freebsd.org/pipermail/freebsd-current/attachments/20121012/e889521e/attachment.sig>


More information about the freebsd-current mailing list