blob: a6aea1d9e10dc4bcab9afcd1deb7a87a2f3dc4c5 [file] [log] [blame]
// INFERNO
#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>
#include <ip.h>
extern char *eve;
/* much stuff not ready yet. */
extern int cflag;
/* this would be good to have; when processes die, keep them around so we can
* debug them.
*/
int keepbroken;
#if 0
void (*serwrite) (char *, int);
struct queue *kscanq; /* keyboard raw scancodes (when needed) */
char *kscanid; /* name of raw scan format (if defined) */
struct queue *kbdq; /* unprocessed console input */
struct queue *lineq; /* processed console input */
struct queue *printq; /* console output */
struct queue *klogq; /* kernel print (log) output */
int iprintscreenputs;
static struct {
rwlock_t rwlock;
Queue *q;
} kprintq;
static struct {
qlock_t qlock;
int raw; /* true if we shouldn't process input */
int ctl; /* number of opens to the control file */
int kbdr; /* number of open reads to the keyboard */
int scan; /* true if reading raw scancodes */
int x; /* index into line */
char line[1024]; /* current input line */
char c;
int count;
int repeat;
} kbd;
#endif
char *sysname = "Your machine";
char *eve = "eve";
enum {
CMreboot,
CMhalt,
CMpanic,
CMbroken,
CMnobroken,
CMconsole,
CMV,
};
static struct cmdtab sysctlcmd[] = {
{CMreboot, "reboot", 0},
{CMhalt, "halt", 0},
{CMpanic, "panic", 0},
{CMconsole, "console", 1},
{CMbroken, "broken", 0},
{CMnobroken, "nobroken", 0},
{CMV, "V", 4},
};
void printinit(void)
{
#if 0
lineq = qopen(2 * 1024, 0, NULL, NULL);
if (lineq == NULL)
panic("printinit");
qnoblock(lineq, 1);
#endif
}
/*
* return true if current user is eve
*/
int iseve(void)
{
#if 0
Osenv *o;
o = up->env;
return strcmp(eve, o->user) == 0;
#endif
return 1;
}
#if 0
static int consactive(void)
{
if (printq)
return qlen(printq) > 0;
return 0;
}
static void prflush(void)
{
uint32_t now;
now = m->ticks;
while (serwrite == NULL && consactive())
if (m->ticks - now >= HZ)
break;
}
/*
* Print a string on the console. Convert \n to \r\n for serial
* line consoles. Locking of the queues is left up to the screen
* or uart code. Multi-line messages to serial consoles may get
* interspersed with other messages.
*/
static void putstrn0(char *str, int n, int usewrite)
{
int m;
char *t;
char buf[PRINTSIZE + 2];
ERRSTACK(1);
/*
* if kprint is open, put the message there, otherwise
* if there's an attached bit mapped display,
* put the message there.
*/
m = consoleprint;
if (canrlock(&(&kprintq)->rwlock)) {
if (kprintq.q != NULL) {
if (waserror()) {
runlock(&(&kprintq)->rwlock);
nexterror();
}
if (usewrite)
qwrite(kprintq.q, str, n);
else
qiwrite(kprintq.q, str, n);
poperror();
m = 0;
}
runlock(&(&kprintq)->rwlock);
}
if (m && screenputs != NULL)
screenputs(str, n);
/*
* if there's a serial line being used as a console,
* put the message there.
*/
if (serwrite != NULL) {
serwrite(str, n);
return;
}
if (printq == 0)
return;
while (n > 0) {
t = memchr(str, '\n', n);
if (t && !kbd.raw) {
m = t - str;
if (m > sizeof(buf) - 2)
m = sizeof(buf) - 2;
memmove(buf, str, m);
buf[m] = '\r';
buf[m + 1] = '\n';
if (usewrite)
qwrite(printq, buf, m + 2);
else
qiwrite(printq, buf, m + 2);
str = t + 1;
n -= m + 1;
} else {
if (usewrite)
qwrite(printq, str, n);
else
qiwrite(printq, str, n);
break;
}
}
}
/*
* mainly for libmp
*/
void sysfatal(char *fmt, ...)
{
va_list arg;
char buf[64];
va_start(arg, fmt);
vsnprintf(buf, sizeof(buf), fmt, arg);
va_end(arg);
error(buf);
}
int pprint(char *fmt, ...)
{
ERRSTACK(1);
int n;
struct chan *c;
Osenv *o;
va_list arg;
char buf[2 * PRINTSIZE];
n = sprint(buf, "%s %ld: ", up->text, up->pid);
va_start(arg, fmt);
n = vseprintf(buf + n, buf + sizeof(buf), fmt, arg) - buf;
va_end(arg);
o = up->env;
if (o->fgrp == 0) {
printd("%s", buf);
return 0;
}
/* TODO: this is probably wrong (VFS hack) */
c = o->fgrp->fd[2];
if (c == 0 || (c->mode != OWRITE && c->mode != ORDWR)) {
printd("%s", buf);
return 0;
}
if (waserror()) {
printd("%s", buf);
poperror();
return 0;
}
devtab[c->type].write(c, buf, n, c->offset);
poperror();
spin_lock(&c->lock);
c->offset += n;
spin_unlock(&c->lock);
return n;
}
void echo(Rune r, char *buf, int n)
{
if (kbd.raw)
return;
if (r == '\n') {
if (printq)
qiwrite(printq, "\r", 1);
} else if (r == 0x15) {
buf = "^U\n";
n = 3;
}
if (consoleprint && screenputs != NULL)
screenputs(buf, n);
if (printq)
qiwrite(printq, buf, n);
}
#endif
#if 0
/*
* Debug key support. Allows other parts of the kernel to register debug
* key handlers, instead of devcons.c having to know whatever's out there.
* A kproc is used to invoke most handlers, rather than tying up the CPU at
* splhi, which can choke some device drivers (eg softmodem).
*/
typedef struct {
Rune r;
char *m;
void (*f) (Rune);
int i; /* function called at interrupt time */
} Dbgkey;
static struct {
Rendez;
Dbgkey *work;
Dbgkey keys[50];
int nkeys;
int on;
} dbg;
static Dbgkey *finddbgkey(Rune r)
{
int i;
Dbgkey *dp;
for (dp = dbg.keys, i = 0; i < dbg.nkeys; i++, dp++)
if (dp->r == r)
return dp;
return NULL;
}
static int dbgwork(void *)
{
return dbg.work != 0;
}
static void dbgproc(void *)
{
Dbgkey *dp;
setpri(PriRealtime);
for (;;) {
do {
rendez_sleep(&dbg, dbgwork, 0);
dp = dbg.work;
} while (dp == NULL);
dp->f(dp->r);
dbg.work = NULL;
}
}
void debugkey(Rune r, char *msg, void (*fcn) (), int iflag)
{
Dbgkey *dp;
if (dbg.nkeys >= ARRAY_SIZE(dbg.keys))
return;
if (finddbgkey(r) != NULL)
return;
for (dp = &dbg.keys[dbg.nkeys++] - 1; dp >= dbg.keys; dp--) {
if (strcmp(dp->m, msg) < 0)
break;
dp[1] = dp[0];
}
dp++;
dp->r = r;
dp->m = msg;
dp->f = fcn;
dp->i = iflag;
}
static int isdbgkey(Rune r)
{
static int ctrlt;
Dbgkey *dp;
int echoctrlt = ctrlt;
/*
* ^t hack BUG
*/
if (dbg.on || (ctrlt >= 2)) {
if (r == 0x14 || r == 0x05) {
ctrlt++;
return 0;
}
if (dp = finddbgkey(r)) {
if (dp->i || ctrlt > 2)
dp->f(r);
else {
dbg.work = dp;
rendez_wakeup(&dbg);
}
ctrlt = 0;
return 1;
}
ctrlt = 0;
} else if (r == 0x14) {
ctrlt++;
return 1;
} else
ctrlt = 0;
if (echoctrlt) {
char buf[3];
buf[0] = 0x14;
while (--echoctrlt >= 0) {
echo(buf[0], buf, 1);
qproduce(kbdq, buf, 1);
}
}
return 0;
}
static void dbgtoggle(Rune)
{
dbg.on = !dbg.on;
printd("Debug keys %s\n", dbg.on ? "HOT" : "COLD");
}
static void dbghelp(void)
{
int i;
Dbgkey *dp;
Dbgkey *dp2;
static char fmt[] = "%c: %-22s";
dp = dbg.keys;
dp2 = dp + (dbg.nkeys + 1) / 2;
for (i = dbg.nkeys; i > 1; i -= 2, dp++, dp2++) {
printd(fmt, dp->r, dp->m);
printd(fmt, dp2->r, dp2->m);
printd("\n");
}
if (i)
printd(fmt, dp->r, dp->m);
printd("\n");
}
static void debuginit(void)
{
ktask("consdbg", dbgproc, NULL);
debugkey('|', "HOT|COLD keys", dbgtoggle, 0);
debugkey('?', "help", dbghelp, 0);
}
#endif
#if 0
/*
* Called by a uart interrupt for console input.
*
* turn '\r' into '\n' before putting it into the queue.
*/
int kbdcr2nl(struct queue *q, int ch)
{
if (ch == '\r')
ch = '\n';
return kbdputc(q, ch);
}
/*
* Put character, possibly a rune, into read queue at interrupt time.
* Performs translation for compose sequences
* Called at interrupt time to process a character.
*/
int kbdputc(struct queue *q, int ch)
{
int n;
char buf[3];
Rune r;
static Rune kc[15];
static int nk, collecting = 0;
r = ch;
if (r == Latin) {
collecting = 1;
nk = 0;
return 0;
}
if (collecting) {
int c;
nk += runetochar((char *unused_char_p_t)&kc[nk], &r);
c = latin1(kc, nk);
if (c < -1) /* need more keystrokes */
return 0;
collecting = 0;
if (c == -1) { /* invalid sequence */
echo(kc[0], (char *unused_char_p_t)kc, nk);
qproduce(q, kc, nk);
return 0;
}
r = (Rune) c;
}
kbd.c = r;
n = runetochar(buf, &r);
if (n == 0)
return 0;
if (!isdbgkey(r)) {
echo(r, buf, n);
qproduce(q, buf, n);
}
return 0;
}
void kbdrepeat(int rep)
{
kbd.repeat = rep;
kbd.count = 0;
}
void kbdclock(void)
{
if (kbd.repeat == 0)
return;
if (kbd.repeat == 1 && ++kbd.count > HZ) {
kbd.repeat = 2;
kbd.count = 0;
return;
}
if (++kbd.count & 1)
kbdputc(kbdq, kbd.c);
}
#endif
enum {
Qdir,
Qcons,
Qsysctl,
Qconsctl,
Qdrivers,
Qhostowner,
Qkeyboard,
Qklog,
Qkprint,
Qscancode,
Qmemory,
Qmsec,
Qnull,
Qrandom,
Qnotquiterandom,
Qsysname,
Qtime,
Quser,
Qjit,
};
static struct dirtab consdir[] = {
{".", {Qdir, 0, QTDIR}, 0, DMDIR | 0555},
{"cons", {Qcons}, 0, 0660},
{"consctl", {Qconsctl}, 0, 0220},
{"sysctl", {Qsysctl}, 0, 0666},
{"drivers", {Qdrivers}, 0, 0444},
{"hostowner", {Qhostowner}, 0, 0644},
{"keyboard", {Qkeyboard}, 0, 0666},
{"klog", {Qklog}, 0, 0444},
{"kprint", {Qkprint}, 0, 0444},
{"scancode", {Qscancode}, 0, 0444},
{"memory", {Qmemory}, 0, 0444},
{"msec", {Qmsec}, NUMSIZE, 0444},
{"null", {Qnull}, 0, 0666},
{"random", {Qrandom}, 0, 0444},
{"notquiterandom", {Qnotquiterandom}, 0, 0444},
{"sysname", {Qsysname}, 0, 0664},
{"time", {Qtime}, 0, 0664},
{"user", {Quser}, 0, 0644},
{"jit", {Qjit}, 0, 0666},
};
uint32_t boottime; /* seconds since epoch at boot */
#if 0
void fddump()
{
struct proc *p;
Osenv *o;
int i;
struct chan *c;
p = proctab(6);
o = p->env;
for (i = 0; i <= o->fgrp->maxfd; i++) {
if ((c = o->fgrp->fd[i]) == NULL)
continue;
printd("%d: %s\n", i, c->name == NULL ? "???" : c->name->s);
}
}
#endif
static void consinit(void)
{
randominit();
#if 0
debuginit();
debugkey('f', "files/6", fddump, 0);
debugkey('q', "panic", qpanic, 1);
debugkey('r', "exit", rexit, 1);
klogq = qopen(128 * 1024, 0, 0, 0);
#endif
}
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 int consstat(struct chan *c, uint8_t * dp, int n)
{
return devstat(c, dp, n, consdir, ARRAY_SIZE(consdir), devgen);
}
#if 0
static void flushkbdline(struct queue *q)
{
if (kbd.x) {
qwrite(q, kbd.line, kbd.x);
kbd.x = 0;
}
}
#endif
static struct chan *consopen(struct chan *c, int omode)
{
c->aux = 0;
#if 0
switch ((uint32_t) c->qid.path) {
case Qconsctl:
if (!iseve())
error(Eperm);
qlock(&(&kbd)->qlock);
kbd.ctl++;
qunlock(&(&kbd)->qlock);
break;
case Qkeyboard:
if ((omode & 3) != OWRITE) {
qlock(&(&kbd)->qlock);
kbd.kbdr++;
flushkbdline(kbdq);
kbd.raw = 1;
qunlock(&(&kbd)->qlock);
}
break;
case Qscancode:
qlock(&(&kbd)->qlock);
if (kscanq || !kscanid) {
qunlock(&(&kbd)->qlock);
c->flag &= ~COPEN;
if (kscanq)
error(Einuse);
else
error(Ebadarg);
}
kscanq = qopen(256, 0, NULL, NULL);
qunlock(&(&kbd)->qlock);
break;
case Qkprint:
if ((omode & 3) != OWRITE) {
wlock(&(&kprintq)->rwlock);
if (kprintq.q != NULL) {
wunlock(&(&kprintq)->rwlock);
error(Einuse);
}
kprintq.q = qopen(32 * 1024, Qcoalesce, NULL, NULL);
if (kprintq.q == NULL) {
wunlock(&(&kprintq)->rwlock);
error(Enomem);
}
qnoblock(kprintq.q, 1);
wunlock(&(&kprintq)->rwlock);
c->iounit = qiomaxatomic;
}
break;
}
#endif
return devopen(c, omode, consdir, ARRAY_SIZE(consdir), devgen);
}
static void consclose(struct chan *c)
{
if ((c->flag & COPEN) == 0)
return;
switch ((uint32_t) c->qid.path) {
#if 0
case Qconsctl:
/* last close of control file turns off raw */
qlock(&(&kbd)->qlock);
if (--kbd.ctl == 0)
kbd.raw = 0;
qunlock(&(&kbd)->qlock);
break;
case Qkeyboard:
if (c->mode != OWRITE) {
qlock(&(&kbd)->qlock);
--kbd.kbdr;
qunlock(&(&kbd)->qlock);
}
break;
case Qscancode:
qlock(&(&kbd)->qlock);
if (kscanq) {
qfree(kscanq);
kscanq = 0;
}
qunlock(&(&kbd)->qlock);
break;
case Qkprint:
wlock(&(&kprintq)->rwlock);
qfree(kprintq.q);
kprintq.q = NULL;
wunlock(&(&kprintq)->rwlock);
break;
#endif
default:
break;
}
}
/* 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 offset)
{
ERRSTACK(1);
int l;
int ch, eol, i;
char *p, tmp[128];
char *cbuf = buf;
if (n <= 0)
return n;
switch ((uint32_t) c->qid.path) {
case Qdir:
return devdirread(c, buf, n, consdir, ARRAY_SIZE(consdir), devgen);
case Qsysctl:
return readstr(offset, buf, n, "akaros");
#if 0
case Qcons:
case Qkeyboard:
qlock(&(&kbd)->qlock);
if (waserror()) {
qunlock(&(&kbd)->qlock);
nexterror();
}
if (kbd.raw || kbd.kbdr) {
if (qcanread(lineq))
n = qread(lineq, buf, n);
else {
/* read as much as possible */
do {
i = qread(kbdq, cbuf, n);
cbuf += i;
n -= i;
} while (n > 0 && qcanread(kbdq));
n = cbuf - (char *unused_char_p_t)buf;
}
} else {
while (!qcanread(lineq)) {
qread(kbdq, &kbd.line[kbd.x], 1);
ch = kbd.line[kbd.x];
eol = 0;
switch (ch) {
case '\b':
if (kbd.x)
kbd.x--;
break;
case 0x15:
kbd.x = 0;
break;
case '\n':
case 0x04:
eol = 1;
default:
kbd.line[kbd.x++] = ch;
break;
}
if (kbd.x == sizeof(kbd.line) || eol) {
if (ch == 0x04)
kbd.x--;
qwrite(lineq, kbd.line, kbd.x);
kbd.x = 0;
}
}
n = qread(lineq, buf, n);
}
qunlock(&(&kbd)->qlock);
poperror();
return n;
case Qscancode:
if (offset == 0)
return readstr(0, buf, n, kscanid);
else
return qread(kscanq, buf, n);
case Qtime:
snprintf(tmp, sizeof(tmp), "%.lld", (int64_t) mseconds() * 1000);
return readstr(offset, buf, n, tmp);
case Qhostowner:
return readstr(offset, buf, n, eve);
case Quser:
return readstr(offset, buf, n, o->user);
case Qjit:
snprintf(tmp, sizeof(tmp), "%d", cflag);
return readstr(offset, buf, n, tmp);
#endif
case Qnull:
return 0;
#if 0
case Qmsec:
return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
#endif
case Qsysname:
if (sysname == NULL)
return 0;
return readstr(offset, buf, n, "Windows 95");
/* not in akaros, inferno was a special case.
case Qnotquiterandom:
genrandom(buf, n);
return n;
*/
case Qrandom:
return randomread(buf, n);
#if 0
case Qmemory:
return poolread(buf, n, offset);
#endif
case Qdrivers:
p = kzmalloc(READSTR, 0);
if (p == NULL)
error(Enomem);
l = 0;
for (i = 0; &devtab[i] < __devtabend; i++)
l += snprintf(p + l, READSTR - l, "#%c %s\n", devtab[i].dc,
devtab[i].name);
if (waserror()) {
kfree(p);
nexterror();
}
n = readstr(offset, buf, n, p);
kfree(p);
poperror();
return n;
case Qklog:
//return qread(klogq, buf, n);
/* 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:
rlock(&(&kprintq)->rwlock);
if (waserror()) {
runlock(&(&kprintq)->rwlock);
nexterror();
}
n = qread(kprintq.q, buf, n);
poperror();
runlock(&(&kprintq)->rwlock);
return n;
#endif
default:
printd("consread %llu\n", c->qid.path);
error(Egreg);
}
return -1; /* never reached */
}
static long conswrite(struct chan *c, void *va, long n, int64_t offset)
{
ERRSTACK(1);
int64_t t;
uint64_t ip;
long l, bp;
char *a = va;
struct cmdbuf *cb;
struct cmdtab *ct;
char buf[256];
int x;
uint64_t rip, rsp, cr3, flags, vcpu;
int ret;
switch ((uint32_t) c->qid.path) {
#if 0
case Qcons:
/*
* Can't page fault in putstrn, so copy the data locally.
*/
l = n;
while (l > 0) {
bp = l;
if (bp > sizeof buf)
bp = sizeof buf;
memmove(buf, a, bp);
putstrn0(a, bp, 1);
a += bp;
l -= bp;
}
break;
case Qconsctl:
if (n >= sizeof(buf))
n = sizeof(buf) - 1;
strncpy(buf, a, n);
buf[n] = 0;
for (a = buf; a;) {
if (strncmp(a, "rawon", 5) == 0) {
qlock(&(&kbd)->qlock);
flushkbdline(kbdq);
kbd.raw = 1;
qunlock(&(&kbd)->qlock);
} else if (strncmp(a, "rawoff", 6) == 0) {
qlock(&(&kbd)->qlock);
kbd.raw = 0;
kbd.x = 0;
qunlock(&(&kbd)->qlock);
}
if (a = strchr(a, ' '))
a++;
}
break;
case Qkeyboard:
for (x = 0; x < n;) {
Rune r;
x += chartorune(&r, &a[x]);
kbdputc(kbdq, r);
}
break;
case Qtime:
if (n >= sizeof(buf))
n = sizeof(buf) - 1;
strncpy(buf, a, n);
buf[n] = 0;
t = strtoll(buf, 0, 0) / 1000000;
boottime = t - TK2SEC(MACHP(0)->ticks);
break;
case Qhostowner:
if (!iseve())
error(Eperm);
if (offset != 0 || n >= sizeof(buf))
error(Ebadarg);
memmove(buf, a, n);
buf[n] = '\0';
if (n > 0 && buf[n - 1] == '\n')
buf[--n] = 0;
if (n <= 0)
error(Ebadarg);
renameuser(eve, buf);
renameproguser(eve, buf);
kstrdup(&eve, buf);
kstrdup(&up->env->user, buf);
break;
case Quser:
if (!iseve())
error(Eperm);
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(&up->env->user, buf);
break;
case Qjit:
if (n >= sizeof(buf))
n = sizeof(buf) - 1;
strncpy(buf, va, n);
buf[n] = '\0';
x = atoi(buf);
if (x < 0 || x > 9)
error(Ebadarg);
cflag = x;
return n;
case Qnull:
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;
#endif
case Qsysctl:
//if (!iseve()) error(Eperm);
cb = parsecmd(a, n);
if (cb->nf > 1)
printk("cons sysctl cmd %s\n", cb->f[0]);
if (waserror()) {
kfree(cb);
nexterror();
}
ct = lookupcmd(cb, sysctlcmd, ARRAY_SIZE(sysctlcmd));
switch (ct->index) {
case CMreboot:
reboot();
break;
case CMhalt:
cpu_halt();
break;
case CMpanic:
panic("sysctl");
//case CMconsole:
//consoleprint = strcmp(cb->f[1], "off") != 0;
break;
case CMbroken:
keepbroken = 1;
break;
case CMnobroken:
keepbroken = 0;
break;
case CMV:
rip = strtoul(cb->f[1], NULL, 0);
rsp = strtoul(cb->f[2], NULL, 0);
cr3 = strtoul(cb->f[3], NULL, 0);
ret = vm_run(rip, rsp, cr3);
printk("vm_run returns %d\n", ret);
n = ret;
break;
}
poperror();
kfree(cb);
break;
default:
printd("conswrite: %llu\n", c->qid.path);
error(Egreg);
}
return n;
}
struct dev consdevtab __devtab = {
'c',
"cons",
devreset,
consinit,
devshutdown,
consattach,
conswalk,
consstat,
consopen,
devcreate,
consclose,
consread,
devbread,
conswrite,
devbwrite,
devremove,
devwstat,
devpower,
devchaninfo,
};
static uint32_t randn;
static void seedrand(void)
{
randomread((void *)&randn, sizeof(randn));
}
int nrand(int n)
{
if (randn == 0)
seedrand();
randn = randn * 1103515245 + 12345 + read_tsc();
return (randn >> 16) % n;
}
int rand(void)
{
nrand(1);
return randn;
}
uint32_t truerand(void)
{
uint32_t x;
randomread(&x, sizeof(x));
return x;
}
/* TODO: qlock_init this, if you ever use this */
qlock_t grandomlk;
void _genrandomqlock(void)
{
qlock(&grandomlk);
}
void _genrandomqunlock(void)
{
qunlock(&grandomlk);
}