Subject: Null console
To: None <tech-kern@NetBSD.org>
From: Dennis Chernoivanov <cdi@mawhrin.net>
List: tech-kern
Date: 10/01/2003 23:26:18
--7iMSBzlTiPOCCT2k
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline


Hi all,

it seems to me that at the moment there is no way to instruct the kernel to
run in a completely headless mode, i.e. without any console device. However,
we need this at least on Cobalt Qube 1 boxes, so I decided to come up with the
following patch. I would appreciate comments and suggestions.

SY,
--cdi

--7iMSBzlTiPOCCT2k
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="nullcons_subr.c"

/*	$NetBSD$	*/

/*-
 * Copyright (c) 2003 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *        This product includes software developed by the NetBSD
 *        Foundation, Inc. and its contributors.
 * 4. Neither the name of The NetBSD Foundation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD$");

#include <sys/param.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/file.h>
#include <sys/conf.h>
#include <sys/vnode.h>

#include <dev/cons.h>


extern struct consdev *cn_tab;		/* physical console device info */

static struct tty *nulltty;		/* null console tty */

cons_decl(null);

dev_type_read(nullcndev_read);
dev_type_ioctl(nullcndev_ioctl);
dev_type_tty(nullcndev_tty);

static int	nullcons_newdev __P((struct consdev *));

const struct cdevsw nullcn_devsw = {
	nullopen, nullclose, nullcndev_read, nullwrite, nullcndev_ioctl,
	nullstop, nullcndev_tty, nopoll, nommap, ttykqfilter, D_TTY
};

/*
 * null console device. We need it because of the ioctl() it handles,
 * which in particular allows control terminal allocation through
 * TIOCSCTTY ioctl. Without the latter, system won't even boot past init(8)
 * invocation.
 */
int
nullcndev_read(dev, uio, flag)
	dev_t dev;
	struct uio *uio;
	int flag;
{

	for(;;);
	return (0);
}

int
nullcndev_ioctl(dev, cmd, data, flag, p)
	dev_t dev;
	u_long cmd;
	caddr_t data;
	int flag;
	struct proc *p;
{
	int error;

	error = (*nulltty->t_linesw->l_ioctl)(nulltty, cmd, data, flag, p);
	if (error != EPASSTHROUGH)
		return (error);

	error = ttioctl(nulltty, cmd, data, flag, p);
	if (error != EPASSTHROUGH)
		return (error);

	return (0);
}

struct tty*
nullcndev_tty(dev)
	dev_t dev;
{

	return nulltty;
}

/*
 * Mark console as no-op (null) console. Proper initialization is deferred
 * to nullconsattach().
 */
void
nullcnprobe(cn)
	struct consdev *cn;
{

	cn->cn_pri = CN_NULL;
	cn->cn_dev = NODEV;
}

/*
 * null console initialization. This includes allocation of a new device and
 * a new tty.
 */
void
nullcninit(cn)
	struct consdev *cn;
{
	static struct consdev nullcn = cons_init(null);

	nullcnprobe(&nullcn);
	cn_tab = &nullcn;
}

/*
 * Dumb getc() implementation. Simply blocks on call.
 */
int
nullcngetc(dev)
	dev_t dev;
{

	for(;;);
	return (0);
}

/*
 * Dumb putc() implementation.
 */
void
nullcnputc(dev, c)
	dev_t dev;
	int c;
{

}

/*
 * Allocate a new console device and a tty to handle console ioctls.
 */
int
nullcons_newdev(cn)
	struct consdev *cn;
{
	int error;
	int bmajor = -1, cmajor = -1;

	if ((cn == NULL) || (cn->cn_pri != CN_NULL) || (cn->cn_dev != NODEV))
		return (0);

	/*
	 * Attach no-op device to the device list.
	 */
	error = devsw_attach("nullcn", NULL, &bmajor, &nullcn_devsw, &cmajor);
	if (error != 0)
		return (error);

	/*
	 * Allocate tty (mostly to have sane ioctl()).
	 */
	nulltty = ttymalloc();
	nulltty->t_dev = makedev(cmajor, 0);
	tty_attach(nulltty);
	cn->cn_dev = nulltty->t_dev;

	return (0);
}

/*
 * Pseudo-device attach function -- it's the right time to do the rest of
 * initialization. 
 */
void
nullconsattach(pdev_count)
	int pdev_count;
{

	nullcons_newdev(cn_tab);
}

--7iMSBzlTiPOCCT2k
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="cobalt.diff"

Index: arch/cobalt/cobalt/console.c
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/cobalt/console.c,v
retrieving revision 1.5
diff -u -r1.5 console.c
--- arch/cobalt/cobalt/console.c	2003/09/12 14:59:11	1.5
+++ arch/cobalt/cobalt/console.c	2003/09/21 11:50:20
@@ -40,21 +40,60 @@
 #include <sys/termios.h>
 
 #include <machine/bus.h>
+#include <machine/nvram.h>
 
 #include <dev/cons.h>
 
 #include <dev/ic/comreg.h>
 #include <dev/ic/comvar.h>
 
+#include "com.h"
+#include "nullcons.h"
+
+dev_type_cnprobe(comcnprobe);
+dev_type_cninit(comcninit);
+
+int	console_present = 0;	/* Do we have a console? */
+
+struct	consdev	constab[] = {
+#if NCOM > 0
+	{ comcnprobe, comcninit, },
+#endif
+#if NNULLCONS > 0
+	{ nullcnprobe, nullcninit },
+#endif
+	{ 0 }
+};
+
+#if NCOM > 0
 #define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
 
 void
-consinit()
+comcnprobe(cn)
+	struct consdev *cn;
 {
-	/* XXX Check NVRAM to see if we should enable the console at all. */
+	/*
+	 * Linux code has a comment that serial console must be probed
+	 * early, otherwise the value which allows to detect serial port
+	 * could be overwritten. Okay, probe here and record the result
+	 * for the future use.
+	 */
+	console_present = *(volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x0020001c);
+	cn->cn_pri = (console_present != 0) ? CN_NORMAL : CN_DEAD;
+}
 
+void
+comcninit(cn)
+	struct consdev *cn;
+{
 	comcnattach(0, 0x1c800000, 115200, COM_FREQ * 10, COM_TYPE_NORMAL,
 	    CONMODE);
+}
+#endif
+
+void
+consinit()
+{
 
-	return;
+	cninit();
 }
Index: arch/cobalt/conf/GENERIC
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/conf/GENERIC,v
retrieving revision 1.45
diff -u -r1.45 GENERIC
--- arch/cobalt/conf/GENERIC	2003/09/07 05:49:57	1.45
+++ arch/cobalt/conf/GENERIC	2003/09/21 11:50:25
@@ -283,6 +283,7 @@
 pseudo-device	rnd				# /dev/random & kernel generator
 #options 	RND_COM				# use "com" randomness (BROKEN)
 pseudo-device	clockctl		# user control of clock subsystem
+pseudo-device	nullcons			# no-op console
 
 # A pseudo device needed for Coda		# also needs CODA (above)
 #pseudo-device	vcoda		4		# coda minicache <-> venus comm.
Index: arch/cobalt/conf/files.cobalt
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/conf/files.cobalt,v
retrieving revision 1.17
diff -u -r1.17 files.cobalt
--- arch/cobalt/conf/files.cobalt	2003/09/12 17:55:47	1.17
+++ arch/cobalt/conf/files.cobalt	2003/09/21 11:50:25
@@ -35,6 +35,7 @@
 file dev/md_root.c			memory_disk_hooks
 
 file dev/cons.c
+file dev/cninit.c
 
 include "dev/i2o/files.i2o"
 
Index: arch/cobalt/dev/com_mainbus.c
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/dev/com_mainbus.c,v
retrieving revision 1.7
diff -u -r1.7 com_mainbus.c
--- arch/cobalt/dev/com_mainbus.c	2003/09/12 17:55:50	1.7
+++ arch/cobalt/dev/com_mainbus.c	2003/09/21 11:50:25
@@ -46,11 +46,14 @@
 #include <machine/autoconf.h>
 #include <machine/intr.h>
 #include <machine/bus.h>
+#include <machine/nvram.h>
 
 #include <dev/ic/comreg.h>
 #include <dev/ic/comvar.h>
 
 
+extern int console_present;
+
 struct com_mainbus_softc {
 	struct com_softc sc_com;
 	void *sc_ih;
@@ -68,9 +71,7 @@
 	struct cfdata *match;
 	void *aux;
 {
-	/* XXX probe */
-
-	return 1;
+	return (console_present != 0);
 }
 
 struct com_softc *com0; /* XXX */
Index: conf/files
===================================================================
RCS file: /cvsroot/src/sys/conf/files,v
retrieving revision 1.632
diff -u -r1.632 files
--- conf/files	2003/09/12 11:20:57	1.632
+++ conf/files	2003/09/21 11:50:51
@@ -957,6 +957,7 @@
 defpseudo tb:		tty
 defpseudo rnd
 defpseudo ksyms
+defpseudo nullcons
 
 defpseudo loop:		ifnet
 defpseudo sl:		ifnet
@@ -1059,6 +1060,7 @@
 file	dev/midisyn.c			midisyn
 file	dev/mm.c
 file	dev/mulaw.c			mulaw
+file	dev/nullcons_subr.c		nullcons		needs-flag
 file	dev/radio.c			radio			needs-flag
 file	dev/rnd.c			rnd			needs-flag
 file	dev/rndpool.c			rnd			needs-flag
Index: dev/cons.c
===================================================================
RCS file: /cvsroot/src/sys/dev/cons.c,v
retrieving revision 1.49
diff -u -r1.49 cons.c
--- dev/cons.c	2003/08/07 16:30:51	1.49
+++ dev/cons.c	2003/09/21 11:50:51
@@ -107,7 +107,7 @@
 };
 
 struct	tty *constty = NULL;	/* virtual console output device */
-struct	consdev *cn_tab;	/* physical console device info */
+struct	consdev *cn_tab = NULL;	/* physical console device info */
 struct	vnode *cn_devvp;	/* vnode for underlying device. */
 
 int
Index: dev/cons.h
===================================================================
RCS file: /cvsroot/src/sys/dev/cons.h,v
retrieving revision 1.21
diff -u -r1.21 cons.h
--- dev/cons.h	2003/08/07 16:30:51	1.21
+++ dev/cons.h	2003/09/21 11:50:51
@@ -103,9 +103,10 @@
 
 /* values for cn_pri - reflect our policy for console selection */
 #define	CN_DEAD		0	/* device doesn't exist */
-#define CN_NORMAL	1	/* device exists but is nothing special */
-#define CN_INTERNAL	2	/* "internal" bit-mapped display */
-#define CN_REMOTE	3	/* serial interface with remote bit set */
+#define CN_NULL		1	/* noop console */
+#define CN_NORMAL	2	/* device exists but is nothing special */
+#define CN_INTERNAL	3	/* "internal" bit-mapped display */
+#define CN_REMOTE	4	/* serial interface with remote bit set */
 
 #ifdef _KERNEL
 
@@ -121,7 +122,10 @@
 void	cnflush __P((void));
 void	cnhalt __P((void));
 void	cnrint __P((void));
+void	nullcnprobe __P((struct consdev *));
+void	nullcninit __P((struct consdev *));
 void	nullcnpollc __P((dev_t, int));
+void	nullconsattach __P((int));
 
 /* console-specific types */
 #define	dev_type_cnprobe(n)	void n __P((struct consdev *))

--7iMSBzlTiPOCCT2k--