blob: 4b929cd106be59fca159f11ef6960063e49faa37 [file] [log] [blame]
#include <vfs.h>
#include <kfs.h>
#include <slab.h>
#include <kmalloc.h>
#include <kref.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <error.h>
#include <cpio.h>
#include <pmap.h>
#include <smp.h>
enum {
Qdir,
Qbintime,
Qcons,
Qconsctl,
Qcputime,
Qdrivers,
Qkmesg,
Qkprint,
Qhostdomain,
Qhostowner,
Qnull,
Qosversion,
Qpgrpid,
Qpid,
Qppid,
Qrandom,
Qreboot,
Qswap,
Qsysname,
Qsysstat,
Qtime,
Quser,
Qzero,
Qdebug,
};
enum {
VLNUMSIZE = 22,
};
static struct dirtab consdir[] = {
{".", {Qdir, 0, QTDIR}, 0, DMDIR | 0555},
{"bintime", {Qbintime}, 24, 0664},
{"cputime", {Qcputime}, 6 * NUMSIZE, 0444},
{"drivers", {Qdrivers}, 0, 0444},
// {"hostdomain", {Qhostdomain}, DOMLEN, 0664},
{"hostowner", {Qhostowner}, 0, 0664},
{"kmesg", {Qkmesg}, 0, 0444,},
{"null", {Qnull}, 0, 0666},
{"osversion", {Qosversion}, 0, 0444},
{"pgrpid", {Qpgrpid}, NUMSIZE, 0444},
{"pid", {Qpid}, NUMSIZE, 0444},
{"ppid", {Qppid}, NUMSIZE, 0444},
{"random", {Qrandom}, 0, 0444},
{"reboot", {Qreboot}, 0, 0664},
{"swap", {Qswap}, 0, 0664},
{"sysname", {Qsysname}, 0, 0664},
{"sysstat", {Qsysstat}, 0, 0666},
{"time", {Qtime}, NUMSIZE + 3 * VLNUMSIZE, 0664},
{"user", {Quser}, 0, 0666},
{"zero", {Qzero}, 0, 0444},
{"debug", {Qdebug}, 0, 0666},
};
static void consinit(void)
{
void randominit(void);
printk("consinit\n");
randominit();
}
static uint32_t randn;
static void
seedrand(void)
{
ERRSTACK(1);
if(!waserror()){
randomread((void*)&randn, sizeof(randn));
poperror();
}
}
int
nrand(int n)
{
if(randn == 0)
seedrand();
randn = randn*1103515245 + 12345 + tsc2msec(read_tsc_serialized());
return (randn>>16) % n;
}
int
rand(void)
{
nrand(1);
return randn;
}
static struct chan *consattach(char *spec)
{
return devattach('c', spec);
}
static struct walkqid *conswalk(struct chan *c, struct chan *nc, char **name,
int nname)
{
return devwalk(c, nc, name, nname, consdir, ARRAY_SIZE(consdir), devgen);
}
static long
consstat(struct chan *c, uint8_t * dp, long n)
{
return devstat(c, dp, n, consdir, ARRAY_SIZE(consdir), devgen);
}
static struct chan *consopen(struct chan *c, int omode)
{
c->aux = NULL;
c = devopen(c, omode, consdir, ARRAY_SIZE(consdir), devgen);
return c;
}
static void consclose(struct chan *c)
{
}
/* we do it this way to avoid the many fun deadlock opportunities
* we keep hitting. And, if you don't suck it
* out soon enough, you lost it. No real effort to ensure goodness
* here as it can get called anywhere. Barret will fix it.
*/
static uint8_t logbuffer[1<<20];
static int index = 0;
static struct queue *logqueue = NULL;
static int reading_kmesg = 0;
void logbuf(int c)
{
if (reading_kmesg)
return;
if (index > 1<<20)
return;
logbuffer[index++] = c;
}
static long
consread(struct chan *c, void *buf, long n, int64_t off)
{
uint32_t l;
char *b, *bp, ch, *s, *e;
char tmp[512]; /* Qswap is 381 bytes at clu */
int i, k, id, send;
long offset, nread;
if (n <= 0)
return n;
nread = n;
offset = off;
switch ((uint32_t) c->qid.path) {
case Qdir:
return devdirread(c, buf, n, consdir, ARRAY_SIZE(consdir), devgen);
case Qcputime:
error("not now");
#if 0
k = offset;
if (k >= 6 * NUMSIZE)
return 0;
if (k + n > 6 * NUMSIZE)
n = 6 * NUMSIZE - k;
/* easiest to format in a separate buffer and copy out */
for (i = 0; i < 6 && NUMSIZE * i < k + n; i++) {
l = current->time[i];
if (i == TReal)
l = sys->ticks - l;
l = TK2MS(l);
readnum(0, tmp + NUMSIZE * i, NUMSIZE, l, NUMSIZE);
}
memmove(buf, tmp + k, n);
#endif
return n;
case Qkmesg:
/* the queue gives us some elasticity for log reading. */
if (! logqueue)
logqueue = qopen(1<<20, 0, 0, 0);
if (logqueue){
int ret;
/* atomic sets/gets are not that important in this case. */
reading_kmesg = 1;
qwrite(logqueue, logbuffer, index);
index = 0;
ret = qread(logqueue, buf, n);
reading_kmesg = 0;
return ret;
}
break;
#if 0
case Qkprint:
return qread(kprintoq, buf, n);
#endif
case Qpgrpid:
return readnum(offset, buf, n, current->pgrp->pgrpid, NUMSIZE);
case Qpid:
return readnum(offset, buf, n, current->pid, NUMSIZE);
#if 0
case Qppid:
return readnum(offset, buf, n, current->parentpid, NUMSIZE);
case Qtime:
return readtime(offset, buf, n);
case Qbintime:
return readbintime(buf, n);
case Qhostowner:
return readstr(offset, buf, n, eve);
case Qhostdomain:
return readstr(offset, buf, n, hostdomain);
case Quser:
return readstr(offset, buf, n, current->user);
#endif
case Qnull:
return 0;
#if 0
case Qsysname:
if (sysname == NULL)
return 0;
return readstr(offset, buf, n, sysname);
#endif
case Qrandom:
return randomread(buf, n);
case Qdrivers:
return devtabread(c, buf, n, off);
case Qzero:
memset(buf, 0, n);
return n;
case Qosversion:
snprintf(tmp, sizeof tmp, "2000");
n = readstr(offset, buf, n, tmp);
return n;
case Qdebug:
#if 0
s = seprint(tmp, tmp + sizeof tmp, "locks %uld\n", lockstats.locks);
s = seprint(s, tmp + sizeof tmp, "glare %uld\n", lockstats.glare);
s = seprint(s, tmp + sizeof tmp, "inglare %uld\n",
lockstats.inglare);
s = seprint(s, tmp + sizeof tmp, "qlock %uld\n", qlockstats.qlock);
seprint(s, tmp + sizeof tmp, "qlockq %uld\n", qlockstats.qlockq);
return readstr(offset, buf, n, tmp);
#endif
return 0;
default:
printd("consread %#llux\n", c->qid.path);
error(Egreg);
}
return -1; /* never reached */
}
static long
conswrite(struct chan *c, void *va, long n, int64_t off)
{
char buf[256], ch;
long l, bp;
char *a;
int i;
uint32_t offset;
struct cmdbuf *cb;
struct cmdtab *ct;
a = va;
offset = off;
switch ((uint32_t) c->qid.path) {
#if 0
case Qtime:
if (!iseve())
error(Eperm);
return writetime(a, n);
case Qbintime:
if (!iseve())
error(Eperm);
return writebintime(a, n);
case Qhostowner:
return hostownerwrite(a, n);
case Qhostdomain:
return hostdomainwrite(a, n);
case Quser:
return userwrite(a, n);
#endif
case Qnull:
break;
#if 0
case Qreboot:
if (!iseve())
error(Eperm);
cb = parsecmd(a, n);
if (waserror()) {
free(cb);
nexterror();
}
ct = lookupcmd(cb, rebootmsg, ARRAY_SIZE(rebootmsg));
switch (ct->index) {
case CMhalt:
reboot(NULL, 0, 0);
break;
case CMreboot:
rebootcmd(cb->nf - 1, cb->f + 1);
break;
case CMpanic:
panic("/dev/reboot");
}
poperror();
free(cb);
break;
case Qsysname:
if (offset != 0)
error(Ebadarg);
if (n <= 0 || n >= sizeof buf)
error(Ebadarg);
strncpy(buf, a, n);
buf[n] = 0;
if (buf[n - 1] == '\n')
buf[n - 1] = 0;
kstrdup(&sysname, buf);
break;
case Qdebug:
if (n >= sizeof(buf))
n = sizeof(buf) - 1;
strncpy(buf, a, n);
buf[n] = 0;
if (n > 0 && buf[n - 1] == '\n')
buf[n - 1] = 0;
error(Ebadctl);
break;
#endif
default:
printd("conswrite: %#llux\n", c->qid.path);
error(Egreg);
}
return n;
}
struct dev miscdevtab = {
'c',
"misc",
devreset,
consinit,
devshutdown,
consattach,
conswalk,
consstat,
consopen,
devcreate,
consclose,
consread,
devbread,
conswrite,
devbwrite,
devremove,
devwstat,
devpower,
devconfig,
devchaninfo,
};