1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7
8 #include "../ip/ip.h"
9
10 enum {
11 Qdir = 0,
12 Qbase,
13
14 Qmax = 16,
15 };
16
17 typedef long Rdwrfn(Chan*, void*, long, vlong);
18
19 static Rdwrfn *readfn[Qmax];
20 static Rdwrfn *writefn[Qmax];
21
22 static Dirtab archdir[Qmax] = {
23 ".", { Qdir, 0, QTDIR }, 0, 0555,
24 };
25
26 Lock archwlock; /* the lock is only for changing archdir */
27 int narchdir = Qbase;
28
29 /*
30 * Add a file to the #P listing. Once added, you can't delete it.
31 * You can't add a file with the same name as one already there,
32 * and you get a pointer to the Dirtab entry so you can do things
33 * like change the Qid version. Changing the Qid path is disallowed.
34 */
35 Dirtab*
addarchfile(char * name,int perm,Rdwrfn * rdfn,Rdwrfn * wrfn)36 addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
37 {
38 int i;
39 Dirtab d;
40 Dirtab *dp;
41
42 memset(&d, 0, sizeof d);
43 strcpy(d.name, name);
44 d.perm = perm;
45
46 lock(&archwlock);
47 if(narchdir >= Qmax){
48 unlock(&archwlock);
49 return nil;
50 }
51
52 for(i=0; i<narchdir; i++)
53 if(strcmp(archdir[i].name, name) == 0){
54 unlock(&archwlock);
55 return nil;
56 }
57
58 d.qid.path = narchdir;
59 archdir[narchdir] = d;
60 readfn[narchdir] = rdfn;
61 writefn[narchdir] = wrfn;
62 dp = &archdir[narchdir++];
63 unlock(&archwlock);
64
65 return dp;
66 }
67
68 static Chan*
archattach(char * spec)69 archattach(char* spec)
70 {
71 return devattach('P', spec);
72 }
73
74 Walkqid*
archwalk(Chan * c,Chan * nc,char ** name,int nname)75 archwalk(Chan* c, Chan *nc, char** name, int nname)
76 {
77 return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
78 }
79
80 static int
archstat(Chan * c,uchar * dp,int n)81 archstat(Chan* c, uchar* dp, int n)
82 {
83 return devstat(c, dp, n, archdir, narchdir, devgen);
84 }
85
86 static Chan*
archopen(Chan * c,int omode)87 archopen(Chan* c, int omode)
88 {
89 return devopen(c, omode, archdir, narchdir, devgen);
90 }
91
92 static void
archclose(Chan *)93 archclose(Chan*)
94 {
95 }
96
97 static long
archread(Chan * c,void * a,long n,vlong offset)98 archread(Chan *c, void *a, long n, vlong offset)
99 {
100 Rdwrfn *fn;
101
102 switch((ulong)c->qid.path){
103 case Qdir:
104 return devdirread(c, a, n, archdir, narchdir, devgen);
105
106 default:
107 if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
108 return fn(c, a, n, offset);
109 error(Eperm);
110 break;
111 }
112
113 return 0;
114 }
115
116 static long
archwrite(Chan * c,void * a,long n,vlong offset)117 archwrite(Chan *c, void *a, long n, vlong offset)
118 {
119 Rdwrfn *fn;
120
121 if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
122 return fn(c, a, n, offset);
123 error(Eperm);
124
125 return 0;
126 }
127
128 Dev archdevtab = {
129 'P',
130 "arch",
131
132 devreset,
133 archinit,
134 devshutdown,
135 archattach,
136 archwalk,
137 archstat,
138 archopen,
139 devcreate,
140 archclose,
141 archread,
142 devbread,
143 archwrite,
144 devbwrite,
145 devremove,
146 devwstat,
147 };
148
149 /* convert m->cputype and pvr register to a string in buf and return buf */
150 char *
cputype2name(char * buf,int size)151 cputype2name(char *buf, int size)
152 {
153 char *s, *es;
154 ulong cputype = getpvr();
155
156 s = buf;
157 es = buf + size;
158 /* ignoring 460, 8xx & 8xxx, e200*, e500* */
159 switch (m->cputype) {
160 case 1:
161 seprint(s, es, "601");
162 break;
163 case 3: case 6: case 7:
164 seprint(s, es, "603");
165 break;
166 case 4: case 9: case 0xa:
167 seprint(s, es, "604");
168 break;
169 case 8: case 0x7000: case 0x7002:
170 seprint(s, es, "G3 7xx");
171 break;
172 case 0x000c: case 0x800c: case 0x8000: case 0x8001:
173 case 0x8002: case 0x8003: case 0x8004:
174 seprint(s, es, "G4 74xx");
175 break;
176 case 0x39: case 0x3c:
177 seprint(s, es, "G5 970");
178 break;
179 case 0x20:
180 seprint(s, es, "403");
181 break;
182 case 0x1291: case 0x4011: case 0x41f1: case 0x5091: case 0x5121:
183 seprint(s, es, "405");
184 break;
185 case 0x2001: /* 200 is Xilinx, 1 is ppc405 */
186 cputype &= ~0xfff;
187 s = seprint(s, es, "Xilinx ");
188 switch (cputype) {
189 case 0x20010000:
190 seprint(s, es, "Virtex-II Pro 405");
191 break;
192 case 0x20011000:
193 seprint(s, es, "Virtex 4 FX 405D5X2");
194 break;
195 default:
196 seprint(s, es, "405");
197 break;
198 }
199 break;
200 case 0x7ff2:
201 s = seprint(s, es, "Xilinx ");
202 if ((cputype & ~0xf) == 0x7ff21910)
203 seprint(s, es, "Virtex 5 FXT 440X5");
204 else
205 seprint(s, es, "440");
206 break;
207 default:
208 /* oddballs */
209 if ((cputype & 0xf0000ff7) == 0x400008d4 ||
210 (cputype & 0xf0000ffb) == 0x200008d0 ||
211 (cputype & 0xf0000ffb) == 0x200008d8 ||
212 (cputype & 0xfff00fff) == 0x53200891 ||
213 (cputype & 0xfff00fff) == 0x53400890 ||
214 (cputype & 0xfff00fff) == 0x53400891) {
215 seprint(s, es, "440");
216 break;
217 }
218 cputype &= 0xf0000fff;
219 switch (cputype) {
220 case 0x40000440: case 0x40000481: case 0x40000850:
221 case 0x40000858: case 0x400008d3: case 0x400008db:
222 case 0x50000850: case 0x50000851: case 0x50000892:
223 case 0x50000894:
224 seprint(s, es, "440");
225 break;
226 default:
227 seprint(s, es, "%#ux", m->cputype);
228 break;
229 }
230 break;
231 }
232 return buf;
233 }
234
235 static long
cputyperead(Chan *,void * a,long n,vlong offset)236 cputyperead(Chan*, void *a, long n, vlong offset)
237 {
238 char name[64], str[128];
239
240 cputype2name(name, sizeof name);
241 snprint(str, sizeof str, "PowerPC %s %lud\n", name, m->cpuhz / 1000000);
242 return readstr(offset, a, n, str);
243 }
244
245 static long
tbread(Chan *,void * a,long n,vlong offset)246 tbread(Chan*, void *a, long n, vlong offset)
247 {
248 char str[16];
249 uvlong tb;
250
251 cycles(&tb);
252
253 snprint(str, sizeof(str), "%16.16llux", tb);
254 return readstr(offset, a, n, str);
255 }
256
257 static long
nsread(Chan *,void * a,long n,vlong offset)258 nsread(Chan*, void *a, long n, vlong offset)
259 {
260 char str[16];
261 uvlong tb;
262
263 cycles(&tb);
264
265 snprint(str, sizeof(str), "%16.16llux", (tb/700)* 1000);
266 return readstr(offset, a, n, str);
267 }
268
269 uvlong
fastns(void)270 fastns(void)
271 {
272 return gettbl();
273 }
274
275 static long
mutread(Chan *,void * a,long n,vlong offset)276 mutread(Chan*, void *a, long n, vlong offset)
277 {
278 char str[256];
279
280 snprint(str, sizeof str, "period (sec.s) %lud\n"
281 "last start sec. %lud\n"
282 "ticks of last mutation %lud\n"
283 "mutations %lud\n"
284 "ticks of average mutation %lud\n"
285 "border %#lux\n",
286 mutstats.period, mutstats.lasttm, mutstats.lastticks,
287 mutstats.count, mutstats.totticks / mutstats.count,
288 qtmborder());
289 return readstr(offset, a, n, str);
290 }
291
292 enum {
293 CMnow,
294 CMperiod,
295 CMstop,
296 };
297
298 Cmdtab mutmsg[] = {
299 CMnow, "now", 1,
300 CMperiod, "period", 2,
301 CMstop, "stop", 1,
302 };
303
304 static long
mutwrite(Chan *,void * a,long n,vlong)305 mutwrite(Chan*, void *a, long n, vlong /* offset */)
306 {
307 Cmdbuf *cb;
308 Cmdtab *ct;
309
310 cb = parsecmd(a, n);
311 if(waserror()) {
312 free(cb);
313 nexterror();
314 }
315 ct = lookupcmd(cb, mutmsg, nelem(mutmsg));
316 switch(ct->index) {
317 case CMnow:
318 if (mutatetrigger() < 0)
319 error("mutate in progress");
320 break;
321 case CMperiod:
322 mutstats.period = atoi(cb->f[1]);
323 break;
324 case CMstop:
325 mutstats.period = 0;
326 break;
327 default:
328 error(Ebadctl);
329 break;
330 }
331 poperror();
332 free(cb);
333 return n;
334 }
335
336 static long
intrsread(Chan *,void * a,long n,vlong offset)337 intrsread(Chan*, void *a, long n, vlong offset)
338 {
339 char *p;
340
341 if(n == 0)
342 return 0;
343 p = malloc(READSTR);
344 intrfmtcounts(p, p + READSTR);
345 n = readstr(offset, a, n, p);
346 free(p);
347 return n;
348 }
349
350 void
archinit(void)351 archinit(void)
352 {
353 addarchfile("cputype", 0444, cputyperead, nil);
354 addarchfile("timebase",0444, tbread, nil);
355 addarchfile("nsec", 0444, nsread, nil);
356 addarchfile("mutate", 0644, mutread, mutwrite);
357 addarchfile("intrs", 0444, intrsread, nil);
358 }
359