blob: fe09574a0efcbabc93a950d33862c2bed4b32e19 [file] [log] [blame]
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
// regression device.
// Currently, has only one file, monitor, which is used to send
// commands to the monitor.
// TODO: read them back :-)
#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 <net/ip.h>
#include <monitor.h>
#include <ktest.h>
struct dev regressdevtab;
static char *devname(void)
{
return regressdevtab.name;
}
struct regress
{
spinlock_t lock;
struct queue *monitor;
};
struct regress regress;
enum{
Monitordirqid = 0,
Monitordataqid,
Monitorctlqid,
};
struct dirtab regresstab[]={
{".", {Monitordirqid, 0, QTDIR}, 0, DMDIR|0550},
{"mondata", {Monitordataqid}, 0, 0600},
{"monctl", {Monitorctlqid}, 0, 0600},
};
static char *ctlcommands = "ktest";
static struct chan *regressattach(char *spec)
{
uint32_t n;
regress.monitor = qopen(2 << 20, 0, 0, 0);
if (! regress.monitor) {
printk("monitor allocate failed. No monitor output\n");
}
return devattach(devname(), spec);
}
static void regressinit(void)
{
}
static struct walkqid *regresswalk(struct chan *c, struct chan *nc, char **name,
unsigned int nname)
{
return devwalk(c, nc, name, nname, regresstab, ARRAY_SIZE(regresstab),
devgen);
}
static size_t regressstat(struct chan *c, uint8_t *db, size_t n)
{
if (regress.monitor)
regresstab[Monitordataqid].length = qlen(regress.monitor);
else
regresstab[Monitordataqid].length = 0;
return devstat(c, db, n, regresstab, ARRAY_SIZE(regresstab), devgen);
}
static struct chan *regressopen(struct chan *c, int omode)
{
if (c->qid.type & QTDIR) {
if (openmode(omode) != O_READ)
error(EPERM, ERROR_FIXME);
}
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
return c;
}
static void regressclose(struct chan *unused)
{
}
static size_t regressread(struct chan *c, void *va, size_t n, off64_t off)
{
uint64_t w, *bp;
char *a, *ea;
uintptr_t offset = off;
uint64_t pc;
int snp_ret, ret = 0;
switch((int)c->qid.path){
case Monitordirqid:
n = devdirread(c, va, n, regresstab, ARRAY_SIZE(regresstab),
devgen);
break;
case Monitorctlqid:
n = readstr(off, va, n, ctlcommands);
break;
case Monitordataqid:
if (regress.monitor) {
printd("monitordataqid: regress.monitor %p len %p\n",
regress.monitor, qlen(kprof.monitor));
if (qlen(regress.monitor) > 0)
n = qread(regress.monitor, va, n);
else
n = 0;
} else
error(EFAIL, "no monitor queue");
break;
default:
n = 0;
break;
}
return n;
}
static size_t regresswrite(struct chan *c, void *a, size_t n, off64_t unused)
{
ERRSTACK(1);
uintptr_t pc;
struct cmdbuf *cb;
cb = parsecmd(a, n);
if (waserror()) {
kfree(cb);
nexterror();
}
switch((int)(c->qid.path)){
case Monitorctlqid:
if(strncmp(a, "ktest", 5) == 0){
run_registered_ktest_suites();
} else {
error(EFAIL, "regresswrite: only commands are %s",
ctlcommands);
}
break;
case Monitordataqid:
if (onecmd(cb->nf, cb->f, NULL) < 0)
n = -1;
break;
default:
error(EBADFD, ERROR_FIXME);
}
kfree(cb);
poperror();
return n;
}
struct dev regressdevtab __devtab = {
.name = "regress",
.reset = devreset,
.init = regressinit,
.shutdown = devshutdown,
.attach = regressattach,
.walk = regresswalk,
.stat = regressstat,
.open = regressopen,
.create = devcreate,
.close = regressclose,
.read = regressread,
.bread = devbread,
.write = regresswrite,
.bwrite = devbwrite,
.remove = devremove,
.wstat = devwstat,
};