Subversion Repositories planix.SVN

Rev

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