Implement ctl command for ktest
[akaros.git] / kern / drivers / dev / regress.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9
10 // regression device.
11 // Currently, has only one file, monitor, which is used to send
12 // commands to the monitor.
13 // TODO: read them back :-)
14
15 #include <vfs.h>
16 #include <kfs.h>
17 #include <slab.h>
18 #include <kmalloc.h>
19 #include <kref.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <assert.h>
23 #include <error.h>
24 #include <cpio.h>
25 #include <pmap.h>
26 #include <smp.h>
27 #include <ip.h>
28 #include <console.h>
29 #include <ktest.h>
30
31 struct regress
32 {
33         spinlock_t lock;
34         struct queue *monitor;
35 };
36 struct regress regress;
37
38 enum{
39         Monitordirqid = 0,
40         Monitordataqid,
41         Monitorctlqid,
42 };
43
44 struct dirtab regresstab[]={
45         {".",           {Monitordirqid, 0, QTDIR},0,    DMDIR|0550},
46         {"mondata",     {Monitordataqid},               0,      0600},
47         {"monctl",      {Monitorctlqid},                0,      0600},
48 };
49
50 static char *ctlcommands = "ktest";
51
52 static struct chan*
53 regressattach(char *spec)
54 {
55         uint32_t n;
56
57         regress.monitor = qopen(2 << 20, 0, 0, 0);
58         if (! regress.monitor) {
59                 printk("monitor allocate failed. No monitor output\n");
60         }
61         return devattach('Z', spec);
62 }
63
64 static void
65 regressinit(void)
66 {
67 }
68
69 static struct walkqid*
70 regresswalk(struct chan *c, struct chan *nc, char **name, int nname)
71 {
72         return devwalk(c, nc, name, nname, regresstab, ARRAY_SIZE(regresstab), devgen);
73 }
74
75 static int
76 regressstat(struct chan *c, uint8_t *db, int n)
77 {
78         if (regress.monitor)
79                 regresstab[Monitordataqid].length = qlen(regress.monitor);
80         else
81                 regresstab[Monitordataqid].length = 0;
82
83         return devstat(c, db, n, regresstab, ARRAY_SIZE(regresstab), devgen);
84 }
85
86 static struct chan*
87 regressopen(struct chan *c, int omode)
88 {
89         if(c->qid.type & QTDIR){
90                 if(openmode(omode) != OREAD)
91                         error(Eperm);
92         }
93         c->mode = openmode(omode);
94         c->flag |= COPEN;
95         c->offset = 0;
96         return c;
97 }
98
99 static void
100 regressclose(struct chan*unused)
101 {
102 }
103
104 static long
105 regressread(struct chan *c, void *va, long n, int64_t off)
106 {
107         uint64_t w, *bp;
108         char *a, *ea;
109         uintptr_t offset = off;
110         uint64_t pc;
111         int snp_ret, ret = 0;
112
113         switch((int)c->qid.path){
114         case Monitordirqid:
115                 n = devdirread(c, va, n, regresstab, ARRAY_SIZE(regresstab), devgen);
116                 break;
117
118         case Monitorctlqid:
119                 n = readstr(off, va, n, ctlcommands);
120                 break;
121
122         case Monitordataqid:
123                 if (regress.monitor) {
124                         printd("monitordataqid: regress.monitor %p len %p\n", regress.monitor, qlen(kprof.monitor));
125                         if (qlen(regress.monitor) > 0)
126                                 n = qread(regress.monitor, va, n);
127                         else
128                                 n = 0;
129                 } else
130                         error("no monitor queue");
131                 break;
132         default:
133                 n = 0;
134                 break;
135         }
136         return n;
137 }
138
139 static long
140 regresswrite(struct chan *c, void *a, long n, int64_t unused)
141 {
142         ERRSTACK(1);
143         uintptr_t pc;
144         struct cmdbuf *cb;
145         cb = parsecmd(a, n);
146
147         if (waserror()) {
148                 kfree(cb);
149                 nexterror();
150         }
151
152         switch((int)(c->qid.path)){
153         case Monitorctlqid:
154                 if(strncmp(a, "ktest", 5) == 0){
155                         run_registered_ktest_suites();
156                 } else {
157                         error("regresswrite: only commands are %s", ctlcommands);
158                 }
159                 break;
160
161         case Monitordataqid:
162                 if (onecmd(cb->nf, cb->f, NULL) < 0)
163                         n = -1;
164                 break;
165         default:
166                 error(Ebadusefd);
167         }
168         kfree(cb);
169         poperror();
170         return n;
171 }
172
173 struct dev regressdevtab __devtab = {
174         'Z',
175         "regress",
176
177         devreset,
178         regressinit,
179         devshutdown,
180         regressattach,
181         regresswalk,
182         regressstat,
183         regressopen,
184         devcreate,
185         regressclose,
186         regressread,
187         devbread,
188         regresswrite,
189         devbwrite,
190         devremove,
191         devwstat,
192 };