| /* | 
 |  * 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 (cb->nf < 1) | 
 | 			error(EFAIL, "%s no command, need %s", __func__, | 
 | 			      ctlcommands); | 
 | 		if (!strcmp(cb->f[0], "ktest")) { | 
 | 			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, | 
 | }; |