1403 lines · 23.8 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h" #include	<authsrv.h> enum{	Nconsdevs	= 64,		/* max number of consoles */ 	/* Consdev flags */	Ciprint		= 2,		/* call this fn from iprint */	Cntorn		= 4,		/* change \n to \r\n */}; typedef struct Consdev Consdev; struct Consdev{	Chan*	c;			/* external file */	Queue*	q;			/* i/o queue, if any */	void	(*fn)(char*, int);	/* i/o function when no queue */	int	flags;}; void	(*consdebug)(void) = nil;void	(*consputs)(char*, int) = nil; static void kmesgputs(char *, int);static void kprintputs(char*, int); static	Lock	consdevslock;static	int	nconsdevs = 3;static	Consdev	consdevs[Nconsdevs] =			/* keep this order */{	{nil, nil,	kmesgputs,	0},			/* kmesg */	{nil, nil,	kprintputs,	Ciprint},		/* kprint */	{nil, nil,	uartputs,	Ciprint|Cntorn},	/* serial */}; static	int	nkbdqs;static	int	nkbdprocs;static	Queue*	kbdqs[Nconsdevs];static	int	kbdprocs[Nconsdevs];static	Queue*	kbdq;		/* unprocessed console input */static	Queue*	lineq;		/* processed console input */static	Queue*	serialoq;	/* serial console output */static	Queue*	kprintoq;	/* console output, for /dev/kprint */static	ulong	kprintinuse;	/* test and set whether /dev/kprint is open */ int	panicking; static struct{	QLock; 	int	raw;		/* true if we shouldn't process input */	Ref	ctl;		/* number of opens to the control file */	int	x;		/* index into line */	char	line[1024];	/* current input line */ 	int	count;	int	ctlpoff; 	/*	 * A place to save up characters at interrupt time	 * before dumping them in the queue	 */	Lock	lockputc;	char	istage[1024];	char	*iw;	char	*ir;	char	*ie;} kbd = {	.iw	= kbd.istage,	.ir	= kbd.istage,	.ie	= kbd.istage + sizeof(kbd.istage),}; char	*sysname;vlong	fasthz; static void	seedrand(void);static int	readtime(ulong, char*, int);static int	readbintime(char*, int);static int	writetime(char*, int);static int	writebintime(char*, int); enum{	CMhalt,	CMreboot,	CMpanic,}; Cmdtab rebootmsg[] ={	CMhalt,		"halt",		1,	CMreboot,	"reboot",	0,	CMpanic,	"panic",	0,}; /* To keep the rest of the kernel unware of new consdevs for now */static voidkprintputs(char *s, int n){	if(consputs != nil)		consputs(s, n);} intaddconsdev(Queue *q, void (*fn)(char*,int), int i, int flags){	Consdev *c; 	ilock(&consdevslock);	if(i < 0)		i = nconsdevs;	else		flags |= consdevs[i].flags;	if(nconsdevs == Nconsdevs)		panic("Nconsdevs too small");	c = &consdevs[i];	c->flags = flags;	c->q = q;	c->fn = fn;	if(i == nconsdevs)		nconsdevs++;	iunlock(&consdevslock);	return i;} voiddelconsdevs(void){	nconsdevs = 2;	/* throw away serial consoles and kprint */	consdevs[1].q = nil;} static voidconskbdqproc(void *a){	char buf[64];	Queue *q;	int nr; 	q = a;	while((nr = qread(q, buf, sizeof(buf))) > 0)		qwrite(kbdq, buf, nr);	pexit("hangup", 1);} static voidkickkbdq(void){	int i; 	if(up != nil && nkbdqs > 1 && nkbdprocs != nkbdqs){		lock(&consdevslock);		if(nkbdprocs == nkbdqs){			unlock(&consdevslock);			return;		}		for(i = 0; i < nkbdqs; i++)			if(kbdprocs[i] == 0){				kbdprocs[i] = 1;				kproc("conskbdq", conskbdqproc, kbdqs[i]);			}		unlock(&consdevslock);	}} intaddkbdq(Queue *q, int i){	int n; 	ilock(&consdevslock);	if(i < 0)		i = nkbdqs++;	if(nkbdqs == Nconsdevs)		panic("Nconsdevs too small");	kbdqs[i] = q;	n = nkbdqs;	iunlock(&consdevslock);	switch(n){	case 1:		/* if there's just one, pull directly from it. */		kbdq = q;		break;	case 2:		/* later we'll merge bytes from all kbdqs into a single kbdq */		kbdq = qopen(4*1024, 0, 0, 0);		if(kbdq == nil)			panic("no kbdq");		/* fall */	default:		kickkbdq();	}	return i;} voidprintinit(void){	lineq = qopen(2*1024, 0, nil, nil);	if(lineq == nil)		panic("printinit");	qnoblock(lineq, 1);} intconsactive(void){	int i;	Queue *q; 	for(i = 0; i < nconsdevs; i++)		if((q = consdevs[i].q) != nil && qlen(q) > 0)			return 1;	return 0;} voidprflush(void){	ulong now; 	now = m->ticks;	while(consactive())		if(m->ticks - now >= HZ)			break;} /* * Log console output so it can be retrieved via /dev/kmesg. * This is good for catching boot-time messages after the fact. */struct {	Lock lk;	char buf[16384];	uint n;} kmesg; static voidkmesgputs(char *str, int n){	uint nn, d; 	ilock(&kmesg.lk);	/* take the tail of huge writes */	if(n > sizeof kmesg.buf){		d = n - sizeof kmesg.buf;		str += d;		n -= d;	} 	/* slide the buffer down to make room */	nn = kmesg.n;	if(nn + n >= sizeof kmesg.buf){		d = nn + n - sizeof kmesg.buf;		if(d)			memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);		nn -= d;	} 	/* copy the data in */	memmove(kmesg.buf+nn, str, n);	nn += n;	kmesg.n = nn;	iunlock(&kmesg.lk);} static voidconsdevputs(Consdev *c, char *s, int n, int usewrite){	Chan *cc;	Queue *q; 	if((cc = c->c) != nil && usewrite)		cc->dev->write(cc, s, n, 0);	else if((q = c->q) != nil && !qisclosed(q))		if(usewrite)			qwrite(q, s, n);		else			qiwrite(q, s, n);	else if(c->fn != nil)		c->fn(s, n);} /* *   Print a string on the console.  Convert \n to \r\n for serial *   line consoles.  Locking of the queues is left up to the screen *   or uart code.  Multi-line messages to serial consoles may get *   interspersed with other messages. */static voidputstrn0(char *str, int n, int usewrite){	Consdev *c;	char *s, *t;	int i, len, m; 	if(!islo())		usewrite = 0; 	for(i = 0; i < nconsdevs; i++){		c = &consdevs[i];		len = n;		s = str;		while(len > 0){			t = nil;			if((c->flags&Cntorn) && !kbd.raw)				t = memchr(s, '\n', len);			if(t != nil && !kbd.raw){				m = t-s;				consdevputs(c, s, m, usewrite);				consdevputs(c, "\r\n", 2, usewrite);				len -= m+1;				s = t+1;			}else{				consdevputs(c, s, len, usewrite);				break;			}		}	}} voidputstrn(char *str, int n){	putstrn0(str, n, 0);} intprint(char *fmt, ...){	int n;	va_list arg;	char buf[PRINTSIZE]; 	va_start(arg, fmt);	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;	va_end(arg);	putstrn(buf, n); 	return n;} /* * Want to interlock iprints to avoid interlaced output on * multiprocessor, but don't want to deadlock if one processor * dies during print and another has something important to say. * Make a good faith effort. */static Lock iprintlock; static intiprintcanlock(Lock *l){	int i; 	for(i=0; i<1000; i++){		if(canlock(l))			return 1;		if(l->m == MACHP(m->machno))			return 0;		microdelay(100);	}	return 0;} intiprint(char *fmt, ...){	Mreg s;	int i, n, locked;	va_list arg;	char buf[PRINTSIZE]; 	s = splhi();	va_start(arg, fmt);	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;	va_end(arg);	locked = iprintcanlock(&iprintlock);	for(i = 0; i < nconsdevs; i++)		if((consdevs[i].flags&Ciprint) != 0)			consdevs[i].fn(buf, n);	if(locked)		unlock(&iprintlock);	splx(s); 	return n;} #pragma profile 0voidpanic(char *fmt, ...){	int n;	Mreg s;	va_list arg;	char buf[PRINTSIZE]; 	consdevs[1].q = nil;	/* don't try to write to /dev/kprint */ 	if(panicking)		for(;;);	panicking = 1; 	s = splhi();	strcpy(buf, "panic: ");	va_start(arg, fmt);	n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;	va_end(arg);	iprint("%s\n", buf);	if(consdebug)		(*consdebug)();	splx(s);	prflush();	buf[n] = '\n';	putstrn(buf, n+1);	dumpstack(); 	exit(1);}#pragma profile 1/* libmp at least contains a few calls to sysfatal; simulate with panic */voidsysfatal(char *fmt, ...){	char err[256];	va_list arg; 	va_start(arg, fmt);	vseprint(err, err + sizeof err, fmt, arg);	va_end(arg);	panic("sysfatal: %s", err);} void_assert(char *fmt){	panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);} intpprint(char *fmt, ...){	int n;	Chan *c;	va_list arg;	char buf[2*PRINTSIZE]; 	if(up == nil || up->fgrp == nil)		return 0; 	c = up->fgrp->fd[2];	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))		return 0;	n = snprint(buf, sizeof buf, "%s %d: ", up->text, up->pid);	va_start(arg, fmt);	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;	va_end(arg); 	if(waserror())		return 0;	c->dev->write(c, buf, n, c->offset);	poperror(); 	lock(c);	c->offset += n;	unlock(c); 	return n;} static voidecho(char *buf, int n){	Mreg s;	static int ctrlt, pid;	char *e, *p; 	if(n == 0)		return; 	e = buf+n;	for(p = buf; p < e; p++){		switch(*p){		case 0x10:	/* ^P */			if(cpuserver && !kbd.ctlpoff){				active.exiting = 1;				return;			}			break;		case 0x14:	/* ^T */

Lines 1–500 of 1403.