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