Add a regression device.
[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
30 struct regress
31 {
32         spinlock_t lock;
33         struct queue *monitor;
34 };
35 struct regress regress;
36
37 enum{
38         Monitordirqid = 0,
39         Monitordataqid,
40         Monitorctlqid,
41 };
42
43 struct dirtab regresstab[]={
44         {".",           {Monitordirqid, 0, QTDIR},0,    DMDIR|0550},
45         {"mondata",     {Monitordataqid},               0,      0600},
46         {"monctl",      {Monitorctlqid},                0,      0600},
47 };
48
49 static size_t mpstatraw_len(void);
50 static size_t mpstat_len(void);
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                 return devdirread(c, va, n, regresstab, ARRAY_SIZE(regresstab), devgen);
116
117         case Monitordataqid:
118                 if (regress.monitor) {
119                         printd("monitordataqid: regress.monitor %p len %p\n", regress.monitor, qlen(kprof.monitor));
120                         if (qlen(regress.monitor) > 0)
121                                 n = qread(regress.monitor, va, n);
122                         else
123                                 n = 0;
124                 } else
125                         error("no monitor queue");
126                 break;
127         default:
128                 n = 0;
129                 break;
130         }
131         return n;
132 }
133
134 static long
135 regresswrite(struct chan *c, void *a, long n, int64_t unused)
136 {
137         ERRSTACK(1);
138         uintptr_t pc;
139         struct cmdbuf *cb;
140         cb = parsecmd(a, n);
141
142         if (waserror()) {
143                 kfree(cb);
144                 nexterror();
145         }
146
147         switch((int)(c->qid.path)){
148         case Monitorctlqid:
149                 error("no ctl commands yet");
150                 break;
151
152         case Monitordataqid:
153                 if (onecmd(cb->nf, cb->f, NULL) < 0)
154                         n = -1;
155                 break;
156         default:
157                 error(Ebadusefd);
158         }
159         kfree(cb);
160         poperror();
161         return n;
162 }
163
164 struct dev regressdevtab __devtab = {
165         'Z',
166         "regress",
167
168         devreset,
169         regressinit,
170         devshutdown,
171         regressattach,
172         regresswalk,
173         regressstat,
174         regressopen,
175         devcreate,
176         regressclose,
177         regressread,
178         devbread,
179         regresswrite,
180         devbwrite,
181         devremove,
182         devwstat,
183 };