Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	"u.h"
2
#include	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"../port/error.h"
7
#include	"pool.h"
8
 
9
#include	<authsrv.h>
10
 
11
void	(*consdebug)(void) = nil;
12
void	(*screenputs)(char*, int) = nil;
13
 
14
Queue*	kbdq;			/* unprocessed console input */
15
Queue*	lineq;			/* processed console input */
16
Queue*	serialoq;		/* serial console output */
17
Queue*	kprintoq;		/* console output, for /dev/kprint */
18
ulong	kprintinuse;		/* test and set whether /dev/kprint is open */
19
int	iprintscreenputs = 1;
20
 
21
int	panicking;
22
 
23
static struct
24
{
25
	QLock;
26
 
27
	int	raw;		/* true if we shouldn't process input */
28
	Ref	ctl;		/* number of opens to the control file */
29
	int	x;		/* index into line */
30
	char	line[1024];	/* current input line */
31
 
32
	int	count;
33
	int	ctlpoff;
34
 
35
	/* a place to save up characters at interrupt time before dumping them in the queue */
36
	Lock	lockputc;
37
	char	istage[1024];
38
	char	*iw;
39
	char	*ir;
40
	char	*ie;
41
} kbd = {
42
	.iw	= kbd.istage,
43
	.ir	= kbd.istage,
44
	.ie	= kbd.istage + sizeof(kbd.istage),
45
};
46
 
47
char	*sysname;
48
vlong	fasthz;
49
 
50
static void	seedrand(void);
51
static int	readtime(ulong, char*, int);
52
static int	readbintime(char*, int);
53
static int	writetime(char*, int);
54
static int	writebintime(char*, int);
55
 
56
enum
57
{
58
	CMhalt,
59
	CMreboot,
60
	CMpanic,
61
};
62
 
63
Cmdtab rebootmsg[] =
64
{
65
	CMhalt,		"halt",		1,
66
	CMreboot,	"reboot",	0,
67
	CMpanic,	"panic",	0,
68
};
69
 
70
void
71
printinit(void)
72
{
73
	lineq = qopen(2*1024, 0, nil, nil);
74
	if(lineq == nil)
75
		panic("printinit");
76
	qnoblock(lineq, 1);
77
}
78
 
79
int
80
consactive(void)
81
{
82
	if(serialoq)
83
		return qlen(serialoq) > 0;
84
	return 0;
85
}
86
 
87
void
88
prflush(void)
89
{
90
	ulong now;
91
 
92
	now = m->ticks;
93
	while(consactive())
94
		if(m->ticks - now >= HZ)
95
			break;
96
}
97
 
98
/*
99
 * Log console output so it can be retrieved via /dev/kmesg.
100
 * This is good for catching boot-time messages after the fact.
101
 */
102
struct {
103
	Lock lk;
104
	char buf[KMESGSIZE];
105
	uint n;
106
} kmesg;
107
 
108
static void
109
kmesgputs(char *str, int n)
110
{
111
	uint nn, d;
112
 
113
	ilock(&kmesg.lk);
114
	/* take the tail of huge writes */
115
	if(n > sizeof kmesg.buf){
116
		d = n - sizeof kmesg.buf;
117
		str += d;
118
		n -= d;
119
	}
120
 
121
	/* slide the buffer down to make room */
122
	nn = kmesg.n;
123
	if(nn + n >= sizeof kmesg.buf){
124
		d = nn + n - sizeof kmesg.buf;
125
		if(d)
126
			memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
127
		nn -= d;
128
	}
129
 
130
	/* copy the data in */
131
	memmove(kmesg.buf+nn, str, n);
132
	nn += n;
133
	kmesg.n = nn;
134
	iunlock(&kmesg.lk);
135
}
136
 
137
/*
138
 *   Print a string on the console.  Convert \n to \r\n for serial
139
 *   line consoles.  Locking of the queues is left up to the screen
140
 *   or uart code.  Multi-line messages to serial consoles may get
141
 *   interspersed with other messages.
142
 */
143
static void
144
putstrn0(char *str, int n, int usewrite)
145
{
146
	int m;
147
	char *t;
148
 
149
	if(!islo())
150
		usewrite = 0;
151
 
152
	/*
153
	 *  how many different output devices do we need?
154
	 */
155
	kmesgputs(str, n);
156
 
157
	/*
158
	 *  if someone is reading /dev/kprint,
159
	 *  put the message there.
160
	 *  if not and there's an attached bit mapped display,
161
	 *  put the message there.
162
	 *
163
	 *  if there's a serial line being used as a console,
164
	 *  put the message there.
165
	 */
166
	if(kprintoq != nil && !qisclosed(kprintoq)){
167
		if(usewrite)
168
			qwrite(kprintoq, str, n);
169
		else
170
			qiwrite(kprintoq, str, n);
171
	}else if(screenputs != nil)
172
		screenputs(str, n);
173
 
174
	if(serialoq == nil){
175
		uartputs(str, n);
176
		return;
177
	}
178
 
179
	while(n > 0) {
180
		t = memchr(str, '\n', n);
181
		if(t && !kbd.raw) {
182
			m = t-str;
183
			if(usewrite){
184
				qwrite(serialoq, str, m);
185
				qwrite(serialoq, "\r\n", 2);
186
			} else {
187
				qiwrite(serialoq, str, m);
188
				qiwrite(serialoq, "\r\n", 2);
189
			}
190
			n -= m+1;
191
			str = t+1;
192
		} else {
193
			if(usewrite)
194
				qwrite(serialoq, str, n);
195
			else
196
				qiwrite(serialoq, str, n);
197
			break;
198
		}
199
	}
200
}
201
 
202
void
203
putstrn(char *str, int n)
204
{
205
	putstrn0(str, n, 0);
206
}
207
 
208
int noprint;
209
 
210
int
211
print(char *fmt, ...)
212
{
213
	int n;
214
	va_list arg;
215
	char buf[PRINTSIZE];
216
 
217
	if(noprint)
218
		return -1;
219
 
220
	va_start(arg, fmt);
221
	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
222
	va_end(arg);
223
	putstrn(buf, n);
224
 
225
	return n;
226
}
227
 
228
/*
229
 * Want to interlock iprints to avoid interlaced output on 
230
 * multiprocessor, but don't want to deadlock if one processor
231
 * dies during print and another has something important to say.
232
 * Make a good faith effort.
233
 */
234
static Lock iprintlock;
235
static int
236
iprintcanlock(Lock *l)
237
{
238
	int i;
239
 
240
	for(i=0; i<1000; i++){
241
		if(canlock(l))
242
			return 1;
243
		if(l->m == MACHP(m->machno))
244
			return 0;
245
		microdelay(100);
246
	}
247
	return 0;
248
}
249
 
250
int
251
iprint(char *fmt, ...)
252
{
253
	int n, s, locked;
254
	va_list arg;
255
	char buf[PRINTSIZE];
256
 
257
	s = splhi();
258
	va_start(arg, fmt);
259
	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
260
	va_end(arg);
261
	locked = iprintcanlock(&iprintlock);
262
	if(screenputs != nil && iprintscreenputs)
263
		screenputs(buf, n);
264
	uartputs(buf, n);
265
	if(locked)
266
		unlock(&iprintlock);
267
	splx(s);
268
 
269
	return n;
270
}
271
 
272
void
273
panic(char *fmt, ...)
274
{
275
	int n, s;
276
	va_list arg;
277
	char buf[PRINTSIZE];
278
 
279
	kprintoq = nil;	/* don't try to write to /dev/kprint */
280
 
281
	if(panicking)
282
		for(;;);
283
	panicking = 1;
284
 
285
	s = splhi();
286
	strcpy(buf, "panic: ");
287
	va_start(arg, fmt);
288
	n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
289
	va_end(arg);
290
	iprint("%s\n", buf);
291
	if(consdebug)
292
		(*consdebug)();
293
	splx(s);
294
	prflush();
295
	buf[n] = '\n';
296
	putstrn(buf, n+1);
297
	dumpstack();
298
 
299
	exit(1);
300
}
301
 
302
/* libmp at least contains a few calls to sysfatal; simulate with panic */
303
void
304
sysfatal(char *fmt, ...)
305
{
306
	char err[256];
307
	va_list arg;
308
 
309
	va_start(arg, fmt);
310
	vseprint(err, err + sizeof err, fmt, arg);
311
	va_end(arg);
312
	panic("sysfatal: %s", err);
313
}
314
 
315
void
316
_assert(char *fmt)
317
{
318
	panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
319
}
320
 
321
int
322
pprint(char *fmt, ...)
323
{
324
	int n;
325
	Chan *c;
326
	va_list arg;
327
	char buf[2*PRINTSIZE];
328
 
329
	if(up == nil || up->fgrp == nil)
330
		return 0;
331
 
332
	c = up->fgrp->fd[2];
333
	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
334
		return 0;
335
	n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
336
	va_start(arg, fmt);
337
	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
338
	va_end(arg);
339
 
340
	if(waserror())
341
		return 0;
342
	devtab[c->type]->write(c, buf, n, c->offset);
343
	poperror();
344
 
345
	lock(c);
346
	c->offset += n;
347
	unlock(c);
348
 
349
	return n;
350
}
351
 
352
static void
353
echoscreen(char *buf, int n)
354
{
355
	char *e, *p;
356
	char ebuf[128];
357
	int x;
358
 
359
	p = ebuf;
360
	e = ebuf + sizeof(ebuf) - 4;
361
	while(n-- > 0){
362
		if(p >= e){
363
			screenputs(ebuf, p - ebuf);
364
			p = ebuf;
365
		}
366
		x = *buf++;
367
		if(x == 0x15){
368
			*p++ = '^';
369
			*p++ = 'U';
370
			*p++ = '\n';
371
		} else
372
			*p++ = x;
373
	}
374
	if(p != ebuf)
375
		screenputs(ebuf, p - ebuf);
376
}
377
 
378
static void
379
echoserialoq(char *buf, int n)
380
{
381
	char *e, *p;
382
	char ebuf[128];
383
	int x;
384
 
385
	p = ebuf;
386
	e = ebuf + sizeof(ebuf) - 4;
387
	while(n-- > 0){
388
		if(p >= e){
389
			qiwrite(serialoq, ebuf, p - ebuf);
390
			p = ebuf;
391
		}
392
		x = *buf++;
393
		if(x == '\n'){
394
			*p++ = '\r';
395
			*p++ = '\n';
396
		} else if(x == 0x15){
397
			*p++ = '^';
398
			*p++ = 'U';
399
			*p++ = '\n';
400
		} else
401
			*p++ = x;
402
	}
403
	if(p != ebuf)
404
		qiwrite(serialoq, ebuf, p - ebuf);
405
}
406
 
407
static void
408
echo(char *buf, int n)
409
{
410
	static int ctrlt, pid;
411
	int x;
412
	char *e, *p;
413
 
414
	if(n == 0)
415
		return;
416
 
417
	e = buf+n;
418
	for(p = buf; p < e; p++){
419
		switch(*p){
420
		case 0x10:	/* ^P */
421
			if(cpuserver && !kbd.ctlpoff){
422
				active.exiting = 1;
423
				return;
424
			}
425
			break;
426
		case 0x14:	/* ^T */
427
			ctrlt++;
428
			if(ctrlt > 2)
429
				ctrlt = 2;
430
			continue;
431
		}
432
 
433
		if(ctrlt != 2)
434
			continue;
435
 
436
		/* ^T escapes */
437
		ctrlt = 0;
438
		switch(*p){
439
		case 'S':
440
			x = splhi();
441
			dumpstack();
442
			procdump();
443
			splx(x);
444
			return;
445
		case 's':
446
			dumpstack();
447
			return;
448
		case 'x':
449
			xsummary();
450
			ixsummary();
451
			mallocsummary();
452
		//	memorysummary();
453
			pagersummary();
454
			return;
455
		case 'd':
456
			if(consdebug == nil)
457
				consdebug = rdb;
458
			else
459
				consdebug = nil;
460
			print("consdebug now %#p\n", consdebug);
461
			return;
462
		case 'D':
463
			if(consdebug == nil)
464
				consdebug = rdb;
465
			consdebug();
466
			return;
467
		case 'p':
468
			x = spllo();
469
			procdump();
470
			splx(x);
471
			return;
472
		case 'q':
473
			scheddump();
474
			return;
475
		case 'k':
476
			killbig("^t ^t k");
477
			return;
478
		case 'r':
479
			exit(0);
480
			return;
481
		}
482
	}
483
 
484
	qproduce(kbdq, buf, n);
485
	if(kbd.raw)
486
		return;
487
	kmesgputs(buf, n);
488
	if(screenputs != nil)
489
		echoscreen(buf, n);
490
	if(serialoq)
491
		echoserialoq(buf, n);
492
}
493
 
494
/*
495
 *  Called by a uart interrupt for console input.
496
 *
497
 *  turn '\r' into '\n' before putting it into the queue.
498
 */
499
int
500
kbdcr2nl(Queue*, int ch)
501
{
502
	char *next;
503
 
504
	ilock(&kbd.lockputc);		/* just a mutex */
505
	if(ch == '\r' && !kbd.raw)
506
		ch = '\n';
507
	next = kbd.iw+1;
508
	if(next >= kbd.ie)
509
		next = kbd.istage;
510
	if(next != kbd.ir){
511
		*kbd.iw = ch;
512
		kbd.iw = next;
513
	}
514
	iunlock(&kbd.lockputc);
515
	return 0;
516
}
517
 
518
/*
519
 *  Put character, possibly a rune, into read queue at interrupt time.
520
 *  Called at interrupt time to process a character.
521
 */
522
int
523
kbdputc(Queue*, int ch)
524
{
525
	int i, n;
526
	char buf[3];
527
	Rune r;
528
	char *next;
529
 
530
	if(kbd.ir == nil)
531
		return 0;		/* in case we're not inited yet */
532
 
533
	ilock(&kbd.lockputc);		/* just a mutex */
534
	r = ch;
535
	n = runetochar(buf, &r);
536
	for(i = 0; i < n; i++){
537
		next = kbd.iw+1;
538
		if(next >= kbd.ie)
539
			next = kbd.istage;
540
		if(next == kbd.ir)
541
			break;
542
		*kbd.iw = buf[i];
543
		kbd.iw = next;
544
	}
545
	iunlock(&kbd.lockputc);
546
	return 0;
547
}
548
 
549
/*
550
 *  we save up input characters till clock time to reduce
551
 *  per character interrupt overhead.
552
 */
553
static void
554
kbdputcclock(void)
555
{
556
	char *iw;
557
 
558
	/* this amortizes cost of qproduce */
559
	if(kbd.iw != kbd.ir){
560
		iw = kbd.iw;
561
		if(iw < kbd.ir){
562
			echo(kbd.ir, kbd.ie-kbd.ir);
563
			kbd.ir = kbd.istage;
564
		}
565
		if(kbd.ir != iw){
566
			echo(kbd.ir, iw-kbd.ir);
567
			kbd.ir = iw;
568
		}
569
	}
570
}
571
 
572
enum{
573
	Qdir,
574
	Qbintime,
575
	Qcons,
576
	Qconsctl,
577
	Qcputime,
578
	Qdrivers,
579
	Qkmesg,
580
	Qkprint,
581
	Qhostdomain,
582
	Qhostowner,
583
	Qnull,
584
	Qosversion,
585
	Qpgrpid,
586
	Qpid,
587
	Qppid,
588
	Qrandom,
589
	Qreboot,
590
	Qswap,
591
	Qsysname,
592
	Qsysstat,
593
	Qtime,
594
	Quser,
595
	Qzero,
596
	Qconfig,
597
};
598
 
599
enum
600
{
601
	VLNUMSIZE=	22,
602
};
603
 
604
static Dirtab consdir[]={
605
	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
606
	"bintime",	{Qbintime},	24,		0664,
607
	"cons",		{Qcons},	0,		0660,
608
	"consctl",	{Qconsctl},	0,		0220,
609
	"cputime",	{Qcputime},	6*NUMSIZE,	0444,
610
	"drivers",	{Qdrivers},	0,		0444,
611
	"hostdomain",	{Qhostdomain},	DOMLEN,		0664,
612
	"hostowner",	{Qhostowner},	0,		0664,
613
	"kmesg",	{Qkmesg},	0,		0440,
614
	"kprint",	{Qkprint, 0, QTEXCL},	0,	DMEXCL|0440,
615
	"null",		{Qnull},	0,		0666,
616
	"osversion",	{Qosversion},	0,		0444,
617
	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444,
618
	"pid",		{Qpid},		NUMSIZE,	0444,
619
	"ppid",		{Qppid},	NUMSIZE,	0444,
620
	"random",	{Qrandom},	0,		0444,
621
	"reboot",	{Qreboot},	0,		0660,
622
	"swap",		{Qswap},	0,		0664,
623
	"sysname",	{Qsysname},	0,		0664,
624
	"sysstat",	{Qsysstat},	0,		0666,
625
	"time",		{Qtime},	NUMSIZE+3*VLNUMSIZE,	0664,
626
	"user",		{Quser},	0,		0666,
627
	"zero",		{Qzero},	0,		0444,
628
	"config",	{Qconfig},	0,		0444,
629
};
630
 
631
int
632
readnum(ulong off, char *buf, ulong n, ulong val, int size)
633
{
634
	char tmp[64];
635
 
636
	snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
637
	tmp[size-1] = ' ';
638
	if(off >= size)
639
		return 0;
640
	if(off+n > size)
641
		n = size-off;
642
	memmove(buf, tmp+off, n);
643
	return n;
644
}
645
 
646
int
647
readstr(ulong off, char *buf, ulong n, char *str)
648
{
649
	int size;
650
 
651
	size = strlen(str);
652
	if(off >= size)
653
		return 0;
654
	if(off+n > size)
655
		n = size-off;
656
	memmove(buf, str+off, n);
657
	return n;
658
}
659
 
660
static void
661
consinit(void)
662
{
663
	todinit();
664
	randominit();
665
	/*
666
	 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
667
	 * processing it every 22 ms should be fine
668
	 */
669
	addclock0link(kbdputcclock, 22);
670
}
671
 
672
static Chan*
673
consattach(char *spec)
674
{
675
	return devattach('c', spec);
676
}
677
 
678
static Walkqid*
679
conswalk(Chan *c, Chan *nc, char **name, int nname)
680
{
681
	return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
682
}
683
 
684
static int
685
consstat(Chan *c, uchar *dp, int n)
686
{
687
	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
688
}
689
 
690
static Chan*
691
consopen(Chan *c, int omode)
692
{
693
	c->aux = nil;
694
	c = devopen(c, omode, consdir, nelem(consdir), devgen);
695
	switch((ulong)c->qid.path){
696
	case Qconsctl:
697
		incref(&kbd.ctl);
698
		break;
699
 
700
	case Qkprint:
701
		if(tas(&kprintinuse) != 0){
702
			c->flag &= ~COPEN;
703
			error(Einuse);
704
		}
705
		if(kprintoq == nil){
706
			kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
707
			if(kprintoq == nil){
708
				c->flag &= ~COPEN;
709
				error(Enomem);
710
			}
711
			qnoblock(kprintoq, 1);
712
		}else
713
			qreopen(kprintoq);
714
		c->iounit = qiomaxatomic;
715
		break;
716
	}
717
	return c;
718
}
719
 
720
static void
721
consclose(Chan *c)
722
{
723
	switch((ulong)c->qid.path){
724
	/* last close of control file turns off raw */
725
	case Qconsctl:
726
		if(c->flag&COPEN){
727
			if(decref(&kbd.ctl) == 0)
728
				kbd.raw = 0;
729
		}
730
		break;
731
 
732
	/* close of kprint allows other opens */
733
	case Qkprint:
734
		if(c->flag & COPEN){
735
			kprintinuse = 0;
736
			qhangup(kprintoq, nil);
737
		}
738
		break;
739
	}
740
}
741
 
742
static long
743
consread(Chan *c, void *buf, long n, vlong off)
744
{
745
	ulong l;
746
	Mach *mp;
747
	char *b, *bp, ch;
748
	char tmp[256];		/* must be >= 18*NUMSIZE (Qswap) */
749
	int i, k, id, send;
750
	vlong offset = off;
751
	extern char configfile[];
752
 
753
	if(n <= 0)
754
		return n;
755
 
756
	switch((ulong)c->qid.path){
757
	case Qdir:
758
		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
759
 
760
	case Qcons:
761
		qlock(&kbd);
762
		if(waserror()) {
763
			qunlock(&kbd);
764
			nexterror();
765
		}
766
		while(!qcanread(lineq)){
767
			if(qread(kbdq, &ch, 1) == 0)
768
				continue;
769
			send = 0;
770
			if(ch == 0){
771
				/* flush output on rawoff -> rawon */
772
				if(kbd.x > 0)
773
					send = !qcanread(kbdq);
774
			}else if(kbd.raw){
775
				kbd.line[kbd.x++] = ch;
776
				send = !qcanread(kbdq);
777
			}else{
778
				switch(ch){
779
				case '\b':
780
					if(kbd.x > 0)
781
						kbd.x--;
782
					break;
783
				case 0x15:	/* ^U */
784
					kbd.x = 0;
785
					break;
786
				case '\n':
787
				case 0x04:	/* ^D */
788
					send = 1;
789
				default:
790
					if(ch != 0x04)
791
						kbd.line[kbd.x++] = ch;
792
					break;
793
				}
794
			}
795
			if(send || kbd.x == sizeof kbd.line){
796
				qwrite(lineq, kbd.line, kbd.x);
797
				kbd.x = 0;
798
			}
799
		}
800
		n = qread(lineq, buf, n);
801
		qunlock(&kbd);
802
		poperror();
803
		return n;
804
 
805
	case Qcputime:
806
		k = offset;
807
		if(k >= 6*NUMSIZE)
808
			return 0;
809
		if(k+n > 6*NUMSIZE)
810
			n = 6*NUMSIZE - k;
811
		/* easiest to format in a separate buffer and copy out */
812
		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
813
			l = up->time[i];
814
			if(i == TReal)
815
				l = MACHP(0)->ticks - l;
816
			l = TK2MS(l);
817
			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
818
		}
819
		memmove(buf, tmp+k, n);
820
		return n;
821
 
822
	case Qkmesg:
823
		/*
824
		 * This is unlocked to avoid tying up a process
825
		 * that's writing to the buffer.  kmesg.n never 
826
		 * gets smaller, so worst case the reader will
827
		 * see a slurred buffer.
828
		 */
829
		if(off >= kmesg.n)
830
			n = 0;
831
		else{
832
			if(off+n > kmesg.n)
833
				n = kmesg.n - off;
834
			memmove(buf, kmesg.buf+off, n);
835
		}
836
		return n;
837
 
838
	case Qkprint:
839
		return qread(kprintoq, buf, n);
840
 
841
	case Qpgrpid:
842
		return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
843
 
844
	case Qpid:
845
		return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
846
 
847
	case Qppid:
848
		return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
849
 
850
	case Qtime:
851
		return readtime((ulong)offset, buf, n);
852
 
853
	case Qbintime:
854
		return readbintime(buf, n);
855
 
856
	case Qhostowner:
857
		return readstr((ulong)offset, buf, n, eve);
858
 
859
	case Qhostdomain:
860
		return readstr((ulong)offset, buf, n, hostdomain);
861
 
862
	case Quser:
863
		return readstr((ulong)offset, buf, n, up->user);
864
 
865
	case Qnull:
866
		return 0;
867
 
868
	case Qconfig:
869
		return readstr((ulong)offset, buf, n, configfile);
870
 
871
	case Qsysstat:
872
		b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1);	/* +1 for NUL */
873
		bp = b;
874
		for(id = 0; id < 32; id++) {
875
			if(active.machs & (1<<id)) {
876
				mp = MACHP(id);
877
				readnum(0, bp, NUMSIZE, id, NUMSIZE);
878
				bp += NUMSIZE;
879
				readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
880
				bp += NUMSIZE;
881
				readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
882
				bp += NUMSIZE;
883
				readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
884
				bp += NUMSIZE;
885
				readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
886
				bp += NUMSIZE;
887
				readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
888
				bp += NUMSIZE;
889
				readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
890
				bp += NUMSIZE;
891
				readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
892
				bp += NUMSIZE;
893
				readnum(0, bp, NUMSIZE,
894
					(mp->perf.avg_inidle*100)/mp->perf.period,
895
					NUMSIZE);
896
				bp += NUMSIZE;
897
				readnum(0, bp, NUMSIZE,
898
					(mp->perf.avg_inintr*100)/mp->perf.period,
899
					NUMSIZE);
900
				bp += NUMSIZE;
901
				*bp++ = '\n';
902
			}
903
		}
904
		if(waserror()){
905
			free(b);
906
			nexterror();
907
		}
908
		n = readstr((ulong)offset, buf, n, b);
909
		free(b);
910
		poperror();
911
		return n;
912
 
913
	case Qswap:
914
		snprint(tmp, sizeof tmp,
915
			"%lud memory\n"
916
			"%d pagesize\n"
917
			"%lud kernel\n"
918
			"%lud/%lud user\n"
919
			"%lud/%lud swap\n"
920
			"%lud/%lud kernel malloc\n"
921
			"%lud/%lud kernel draw\n",
922
			conf.npage*BY2PG,
923
			BY2PG,
924
			conf.npage-conf.upages,
925
			palloc.user-palloc.freecount, palloc.user,
926
			conf.nswap-swapalloc.free, conf.nswap,
927
			mainmem->cursize, mainmem->maxsize,
928
			imagmem->cursize, imagmem->maxsize);
929
 
930
		return readstr((ulong)offset, buf, n, tmp);
931
 
932
	case Qsysname:
933
		if(sysname == nil)
934
			return 0;
935
		return readstr((ulong)offset, buf, n, sysname);
936
 
937
	case Qrandom:
938
		return randomread(buf, n);
939
 
940
	case Qdrivers:
941
		b = malloc(READSTR);
942
		if(b == nil)
943
			error(Enomem);
944
		k = 0;
945
		for(i = 0; devtab[i] != nil; i++)
946
			k += snprint(b+k, READSTR-k, "#%C %s\n",
947
				devtab[i]->dc, devtab[i]->name);
948
		if(waserror()){
949
			free(b);
950
			nexterror();
951
		}
952
		n = readstr((ulong)offset, buf, n, b);
953
		free(b);
954
		poperror();
955
		return n;
956
 
957
	case Qzero:
958
		memset(buf, 0, n);
959
		return n;
960
 
961
	case Qosversion:
962
		snprint(tmp, sizeof tmp, "2000");
963
		n = readstr((ulong)offset, buf, n, tmp);
964
		return n;
965
 
966
	default:
967
		print("consread %#llux\n", c->qid.path);
968
		error(Egreg);
969
	}
970
	return -1;		/* never reached */
971
}
972
 
973
static long
974
conswrite(Chan *c, void *va, long n, vlong off)
975
{
976
	char buf[256], ch;
977
	long l, bp;
978
	char *a;
979
	Mach *mp;
980
	int id, fd;
981
	Chan *swc;
982
	ulong offset;
983
	Cmdbuf *cb;
984
	Cmdtab *ct;
985
 
986
	a = va;
987
	offset = off;
988
 
989
	switch((ulong)c->qid.path){
990
	case Qcons:
991
		/*
992
		 * Can't page fault in putstrn, so copy the data locally.
993
		 */
994
		l = n;
995
		while(l > 0){
996
			bp = l;
997
			if(bp > sizeof buf)
998
				bp = sizeof buf;
999
			memmove(buf, a, bp);
1000
			putstrn0(buf, bp, 1);
1001
			a += bp;
1002
			l -= bp;
1003
		}
1004
		break;
1005
 
1006
	case Qconsctl:
1007
		if(n >= sizeof(buf))
1008
			n = sizeof(buf)-1;
1009
		strncpy(buf, a, n);
1010
		buf[n] = 0;
1011
		for(a = buf; a;){
1012
			if(strncmp(a, "rawon", 5) == 0){
1013
				kbd.raw = 1;
1014
				/* clumsy hack - wake up reader */
1015
				ch = 0;
1016
				qwrite(kbdq, &ch, 1);			
1017
			} else if(strncmp(a, "rawoff", 6) == 0){
1018
				kbd.raw = 0;
1019
			} else if(strncmp(a, "ctlpon", 6) == 0){
1020
				kbd.ctlpoff = 0;
1021
			} else if(strncmp(a, "ctlpoff", 7) == 0){
1022
				kbd.ctlpoff = 1;
1023
			}
1024
			if(a = strchr(a, ' '))
1025
				a++;
1026
		}
1027
		break;
1028
 
1029
	case Qtime:
1030
		if(!iseve())
1031
			error(Eperm);
1032
		return writetime(a, n);
1033
 
1034
	case Qbintime:
1035
		if(!iseve())
1036
			error(Eperm);
1037
		return writebintime(a, n);
1038
 
1039
	case Qhostowner:
1040
		return hostownerwrite(a, n);
1041
 
1042
	case Qhostdomain:
1043
		return hostdomainwrite(a, n);
1044
 
1045
	case Quser:
1046
		return userwrite(a, n);
1047
 
1048
	case Qnull:
1049
		break;
1050
 
1051
	case Qconfig:
1052
		error(Eperm);
1053
		break;
1054
 
1055
	case Qreboot:
1056
		if(!iseve())
1057
			error(Eperm);
1058
		cb = parsecmd(a, n);
1059
 
1060
		if(waserror()) {
1061
			free(cb);
1062
			nexterror();
1063
		}
1064
		ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
1065
		switch(ct->index) {
1066
		case CMhalt:
1067
			reboot(nil, 0, 0);
1068
			break;
1069
		case CMreboot:
1070
			rebootcmd(cb->nf-1, cb->f+1);
1071
			break;
1072
		case CMpanic:
1073
			*(ulong*)0=0;
1074
			panic("/dev/reboot");
1075
		}
1076
		poperror();
1077
		free(cb);
1078
		break;
1079
 
1080
	case Qsysstat:
1081
		for(id = 0; id < 32; id++) {
1082
			if(active.machs & (1<<id)) {
1083
				mp = MACHP(id);
1084
				mp->cs = 0;
1085
				mp->intr = 0;
1086
				mp->syscall = 0;
1087
				mp->pfault = 0;
1088
				mp->tlbfault = 0;
1089
				mp->tlbpurge = 0;
1090
			}
1091
		}
1092
		break;
1093
 
1094
	case Qswap:
1095
		if(n >= sizeof buf)
1096
			error(Egreg);
1097
		memmove(buf, va, n);	/* so we can NUL-terminate */
1098
		buf[n] = 0;
1099
		/* start a pager if not already started */
1100
		if(strncmp(buf, "start", 5) == 0){
1101
			kickpager();
1102
			break;
1103
		}
1104
		if(!iseve())
1105
			error(Eperm);
1106
		if(buf[0]<'0' || '9'<buf[0])
1107
			error(Ebadarg);
1108
		fd = strtoul(buf, 0, 0);
1109
		swc = fdtochan(fd, -1, 1, 1);
1110
		setswapchan(swc);
1111
		break;
1112
 
1113
	case Qsysname:
1114
		if(offset != 0)
1115
			error(Ebadarg);
1116
		if(n <= 0 || n >= sizeof buf)
1117
			error(Ebadarg);
1118
		strncpy(buf, a, n);
1119
		buf[n] = 0;
1120
		if(buf[n-1] == '\n')
1121
			buf[n-1] = 0;
1122
		kstrdup(&sysname, buf);
1123
		break;
1124
 
1125
	default:
1126
		print("conswrite: %#llux\n", c->qid.path);
1127
		error(Egreg);
1128
	}
1129
	return n;
1130
}
1131
 
1132
Dev consdevtab = {
1133
	'c',
1134
	"cons",
1135
 
1136
	devreset,
1137
	consinit,
1138
	devshutdown,
1139
	consattach,
1140
	conswalk,
1141
	consstat,
1142
	consopen,
1143
	devcreate,
1144
	consclose,
1145
	consread,
1146
	devbread,
1147
	conswrite,
1148
	devbwrite,
1149
	devremove,
1150
	devwstat,
1151
};
1152
 
1153
static	ulong	randn;
1154
 
1155
static void
1156
seedrand(void)
1157
{
1158
	if(!waserror()){
1159
		randomread((void*)&randn, sizeof(randn));
1160
		poperror();
1161
	}
1162
}
1163
 
1164
int
1165
nrand(int n)
1166
{
1167
	if(randn == 0)
1168
		seedrand();
1169
	randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
1170
	return (randn>>16) % n;
1171
}
1172
 
1173
int
1174
rand(void)
1175
{
1176
	nrand(1);
1177
	return randn;
1178
}
1179
 
1180
static uvlong uvorder = 0x0001020304050607ULL;
1181
 
1182
static uchar*
1183
le2vlong(vlong *to, uchar *f)
1184
{
1185
	uchar *t, *o;
1186
	int i;
1187
 
1188
	t = (uchar*)to;
1189
	o = (uchar*)&uvorder;
1190
	for(i = 0; i < sizeof(vlong); i++)
1191
		t[o[i]] = f[i];
1192
	return f+sizeof(vlong);
1193
}
1194
 
1195
static uchar*
1196
vlong2le(uchar *t, vlong from)
1197
{
1198
	uchar *f, *o;
1199
	int i;
1200
 
1201
	f = (uchar*)&from;
1202
	o = (uchar*)&uvorder;
1203
	for(i = 0; i < sizeof(vlong); i++)
1204
		t[i] = f[o[i]];
1205
	return t+sizeof(vlong);
1206
}
1207
 
1208
static long order = 0x00010203;
1209
 
1210
static uchar*
1211
le2long(long *to, uchar *f)
1212
{
1213
	uchar *t, *o;
1214
	int i;
1215
 
1216
	t = (uchar*)to;
1217
	o = (uchar*)&order;
1218
	for(i = 0; i < sizeof(long); i++)
1219
		t[o[i]] = f[i];
1220
	return f+sizeof(long);
1221
}
1222
 
1223
static uchar*
1224
long2le(uchar *t, long from)
1225
{
1226
	uchar *f, *o;
1227
	int i;
1228
 
1229
	f = (uchar*)&from;
1230
	o = (uchar*)&order;
1231
	for(i = 0; i < sizeof(long); i++)
1232
		t[i] = f[o[i]];
1233
	return t+sizeof(long);
1234
}
1235
 
1236
char *Ebadtimectl = "bad time control";
1237
 
1238
/*
1239
 *  like the old #c/time but with added info.  Return
1240
 *
1241
 *	secs	nanosecs	fastticks	fasthz
1242
 */
1243
static int
1244
readtime(ulong off, char *buf, int n)
1245
{
1246
	vlong	nsec, ticks;
1247
	long sec;
1248
	char str[7*NUMSIZE];
1249
 
1250
	nsec = todget(&ticks);
1251
	if(fasthz == 0LL)
1252
		fastticks((uvlong*)&fasthz);
1253
	sec = nsec/1000000000ULL;
1254
	snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
1255
		NUMSIZE-1, sec,
1256
		VLNUMSIZE-1, nsec,
1257
		VLNUMSIZE-1, ticks,
1258
		VLNUMSIZE-1, fasthz);
1259
	return readstr(off, buf, n, str);
1260
}
1261
 
1262
/*
1263
 *  set the time in seconds
1264
 */
1265
static int
1266
writetime(char *buf, int n)
1267
{
1268
	char b[13];
1269
	long i;
1270
	vlong now;
1271
 
1272
	if(n >= sizeof(b))
1273
		error(Ebadtimectl);
1274
	strncpy(b, buf, n);
1275
	b[n] = 0;
1276
	i = strtol(b, 0, 0);
1277
	if(i <= 0)
1278
		error(Ebadtimectl);
1279
	now = i*1000000000LL;
1280
	todset(now, 0, 0);
1281
	return n;
1282
}
1283
 
1284
/*
1285
 *  read binary time info.  all numbers are little endian.
1286
 *  ticks and nsec are syncronized.
1287
 */
1288
static int
1289
readbintime(char *buf, int n)
1290
{
1291
	int i;
1292
	vlong nsec, ticks;
1293
	uchar *b = (uchar*)buf;
1294
 
1295
	i = 0;
1296
	if(fasthz == 0LL)
1297
		fastticks((uvlong*)&fasthz);
1298
	nsec = todget(&ticks);
1299
	if(n >= 3*sizeof(uvlong)){
1300
		vlong2le(b+2*sizeof(uvlong), fasthz);
1301
		i += sizeof(uvlong);
1302
	}
1303
	if(n >= 2*sizeof(uvlong)){
1304
		vlong2le(b+sizeof(uvlong), ticks);
1305
		i += sizeof(uvlong);
1306
	}
1307
	if(n >= 8){
1308
		vlong2le(b, nsec);
1309
		i += sizeof(vlong);
1310
	}
1311
	return i;
1312
}
1313
 
1314
/*
1315
 *  set any of the following
1316
 *	- time in nsec
1317
 *	- nsec trim applied over some seconds
1318
 *	- clock frequency
1319
 */
1320
static int
1321
writebintime(char *buf, int n)
1322
{
1323
	uchar *p;
1324
	vlong delta;
1325
	long period;
1326
 
1327
	n--;
1328
	p = (uchar*)buf + 1;
1329
	switch(*buf){
1330
	case 'n':
1331
		if(n < sizeof(vlong))
1332
			error(Ebadtimectl);
1333
		le2vlong(&delta, p);
1334
		todset(delta, 0, 0);
1335
		break;
1336
	case 'd':
1337
		if(n < sizeof(vlong)+sizeof(long))
1338
			error(Ebadtimectl);
1339
		p = le2vlong(&delta, p);
1340
		le2long(&period, p);
1341
		todset(-1, delta, period);
1342
		break;
1343
	case 'f':
1344
		if(n < sizeof(uvlong))
1345
			error(Ebadtimectl);
1346
		le2vlong(&fasthz, p);
1347
		if(fasthz <= 0)
1348
			error(Ebadtimectl);
1349
		todsetfreq(fasthz);
1350
		break;
1351
	}
1352
	return n;
1353
}