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 "ureg.h"
9
10 typedef struct IOMap IOMap;
11 struct IOMap
12 {
13 IOMap *next;
14 int reserved;
15 char tag[13];
16 ulong start;
17 ulong end;
18 };
19
20 static struct
21 {
22 Lock;
23 IOMap *map;
24 IOMap *free;
25 IOMap maps[32]; // some initial free maps
26
27 QLock ql; // lock for reading map
28 } iomap;
29
30 enum {
31 Qdir = 0,
32 Qioalloc = 1,
33 Qiob,
34 Qiow,
35 Qiol,
36 Qbase,
37
38 Qmax = 16,
39 };
40
41 typedef long Rdwrfn(Chan*, void*, long, vlong);
42
43 static Rdwrfn *readfn[Qmax];
44 static Rdwrfn *writefn[Qmax];
45
46 static Dirtab archdir[Qmax] = {
47 ".", { Qdir, 0, QTDIR }, 0, 0555,
48 "ioalloc", { Qioalloc, 0 }, 0, 0444,
49 "iob", { Qiob, 0 }, 0, 0660,
50 "iow", { Qiow, 0 }, 0, 0660,
51 "iol", { Qiol, 0 }, 0, 0660,
52 };
53 Lock archwlock; /* the lock is only for changing archdir */
54 int narchdir = Qbase;
55
56 /*
57 * Add a file to the #P listing. Once added, you can't delete it.
58 * You can't add a file with the same name as one already there,
59 * and you get a pointer to the Dirtab entry so you can do things
60 * like change the Qid version. Changing the Qid path is disallowed.
61 */
62 Dirtab*
addarchfile(char * name,int perm,Rdwrfn * rdfn,Rdwrfn * wrfn)63 addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
64 {
65 int i;
66 Dirtab d;
67 Dirtab *dp;
68
69 memset(&d, 0, sizeof d);
70 strcpy(d.name, name);
71 d.perm = perm;
72
73 lock(&archwlock);
74 if(narchdir >= Qmax){
75 unlock(&archwlock);
76 return nil;
77 }
78
79 for(i=0; i<narchdir; i++)
80 if(strcmp(archdir[i].name, name) == 0){
81 unlock(&archwlock);
82 return nil;
83 }
84
85 d.qid.path = narchdir;
86 archdir[narchdir] = d;
87 readfn[narchdir] = rdfn;
88 writefn[narchdir] = wrfn;
89 dp = &archdir[narchdir++];
90 unlock(&archwlock);
91
92 return dp;
93 }
94
95 void
ioinit(void)96 ioinit(void)
97 {
98 char *excluded;
99 int i;
100
101 for(i = 0; i < nelem(iomap.maps)-1; i++)
102 iomap.maps[i].next = &iomap.maps[i+1];
103 iomap.maps[i].next = nil;
104 iomap.free = iomap.maps;
105
106 /*
107 * Someone needs to explain why this was here...
108 */
109 ioalloc(0x0fff, 1, 0, "dummy"); // i82557 is at 0x1000, the dummy
110 // entry is needed for swappable devs.
111
112 if ((excluded = getconf("ioexclude")) != nil) {
113 char *s;
114
115 s = excluded;
116 while (s && *s != '\0' && *s != '\n') {
117 char *ends;
118 int io_s, io_e;
119
120 io_s = (int)strtol(s, &ends, 0);
121 if (ends == nil || ends == s || *ends != '-') {
122 print("ioinit: cannot parse option string\n");
123 break;
124 }
125 s = ++ends;
126
127 io_e = (int)strtol(s, &ends, 0);
128 if (ends && *ends == ',')
129 *ends++ = '\0';
130 s = ends;
131
132 ioalloc(io_s, io_e - io_s + 1, 0, "pre-allocated");
133 }
134 }
135
136 }
137
138 // Reserve a range to be ioalloced later.
139 // This is in particular useful for exchangable cards, such
140 // as pcmcia and cardbus cards.
141 int
ioreserve(int,int size,int align,char * tag)142 ioreserve(int, int size, int align, char *tag)
143 {
144 IOMap *map, **l;
145 int i, port;
146
147 lock(&iomap);
148 // find a free port above 0x400 and below 0x1000
149 port = 0x400;
150 for(l = &iomap.map; *l; l = &(*l)->next){
151 map = *l;
152 if (map->start < 0x400)
153 continue;
154 i = map->start - port;
155 if(i > size)
156 break;
157 if(align > 0)
158 port = ((port+align-1)/align)*align;
159 else
160 port = map->end;
161 }
162 if(*l == nil){
163 unlock(&iomap);
164 return -1;
165 }
166 map = iomap.free;
167 if(map == nil){
168 print("ioalloc: out of maps");
169 unlock(&iomap);
170 return port;
171 }
172 iomap.free = map->next;
173 map->next = *l;
174 map->start = port;
175 map->end = port + size;
176 map->reserved = 1;
177 strncpy(map->tag, tag, sizeof(map->tag));
178 map->tag[sizeof(map->tag)-1] = 0;
179 *l = map;
180
181 archdir[0].qid.vers++;
182
183 unlock(&iomap);
184 return map->start;
185 }
186
187 //
188 // alloc some io port space and remember who it was
189 // alloced to. if port < 0, find a free region.
190 //
191 int
ioalloc(int port,int size,int align,char * tag)192 ioalloc(int port, int size, int align, char *tag)
193 {
194 IOMap *map, **l;
195 int i;
196
197 lock(&iomap);
198 if(port < 0){
199 // find a free port above 0x400 and below 0x1000
200 port = 0x400;
201 for(l = &iomap.map; *l; l = &(*l)->next){
202 map = *l;
203 if (map->start < 0x400)
204 continue;
205 i = map->start - port;
206 if(i > size)
207 break;
208 if(align > 0)
209 port = ((port+align-1)/align)*align;
210 else
211 port = map->end;
212 }
213 if(*l == nil){
214 unlock(&iomap);
215 return -1;
216 }
217 } else {
218 // Only 64KB I/O space on the x86.
219 if((port+size) > 0x10000){
220 unlock(&iomap);
221 return -1;
222 }
223 // see if the space clashes with previously allocated ports
224 for(l = &iomap.map; *l; l = &(*l)->next){
225 map = *l;
226 if(map->end <= port)
227 continue;
228 if(map->reserved && map->start == port && map->end == port + size) {
229 map->reserved = 0;
230 unlock(&iomap);
231 return map->start;
232 }
233 if(map->start >= port+size)
234 break;
235 unlock(&iomap);
236 return -1;
237 }
238 }
239 map = iomap.free;
240 if(map == nil){
241 print("ioalloc: out of maps");
242 unlock(&iomap);
243 return port;
244 }
245 iomap.free = map->next;
246 map->next = *l;
247 map->start = port;
248 map->end = port + size;
249 strncpy(map->tag, tag, sizeof(map->tag));
250 map->tag[sizeof(map->tag)-1] = 0;
251 *l = map;
252
253 archdir[0].qid.vers++;
254
255 unlock(&iomap);
256 return map->start;
257 }
258
259 void
iofree(int port)260 iofree(int port)
261 {
262 IOMap *map, **l;
263
264 lock(&iomap);
265 for(l = &iomap.map; *l; l = &(*l)->next){
266 if((*l)->start == port){
267 map = *l;
268 *l = map->next;
269 map->next = iomap.free;
270 iomap.free = map;
271 break;
272 }
273 if((*l)->start > port)
274 break;
275 }
276 archdir[0].qid.vers++;
277 unlock(&iomap);
278 }
279
280 int
iounused(int start,int end)281 iounused(int start, int end)
282 {
283 IOMap *map;
284
285 for(map = iomap.map; map; map = map->next){
286 if(start >= map->start && start < map->end
287 || start <= map->start && end > map->start)
288 return 0;
289 }
290 return 1;
291 }
292
293 static void
checkport(int start,int end)294 checkport(int start, int end)
295 {
296 /* standard vga regs are OK */
297 if(start >= 0x2b0 && end <= 0x2df+1)
298 return;
299 if(start >= 0x3c0 && end <= 0x3da+1)
300 return;
301
302 if(iounused(start, end))
303 return;
304 error(Eperm);
305 }
306
307 static Chan*
archattach(char * spec)308 archattach(char* spec)
309 {
310 return devattach('P', spec);
311 }
312
313 Walkqid*
archwalk(Chan * c,Chan * nc,char ** name,int nname)314 archwalk(Chan* c, Chan *nc, char** name, int nname)
315 {
316 return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
317 }
318
319 static long
archstat(Chan * c,uchar * dp,long n)320 archstat(Chan* c, uchar* dp, long n)
321 {
322 return devstat(c, dp, n, archdir, narchdir, devgen);
323 }
324
325 static Chan*
archopen(Chan * c,int omode)326 archopen(Chan* c, int omode)
327 {
328 return devopen(c, omode, archdir, narchdir, devgen);
329 }
330
331 static void
archclose(Chan *)332 archclose(Chan*)
333 {
334 }
335
336 enum
337 {
338 Linelen= 31,
339 };
340
341 static long
archread(Chan * c,void * a,long n,vlong offset)342 archread(Chan *c, void *a, long n, vlong offset)
343 {
344 char *buf, *p;
345 int port;
346 ushort *sp;
347 ulong *lp;
348 IOMap *map;
349 Rdwrfn *fn;
350
351 switch((ulong)c->qid.path){
352
353 case Qdir:
354 return devdirread(c, a, n, archdir, narchdir, devgen);
355
356 case Qiob:
357 port = offset;
358 checkport(offset, offset+n);
359 for(p = a; port < offset+n; port++)
360 *p++ = inb(port);
361 return n;
362
363 case Qiow:
364 if(n & 1)
365 error(Ebadarg);
366 checkport(offset, offset+n);
367 sp = a;
368 for(port = offset; port < offset+n; port += 2)
369 *sp++ = ins(port);
370 return n;
371
372 case Qiol:
373 if(n & 3)
374 error(Ebadarg);
375 checkport(offset, offset+n);
376 lp = a;
377 for(port = offset; port < offset+n; port += 4)
378 *lp++ = inl(port);
379 return n;
380
381 case Qioalloc:
382 break;
383
384 default:
385 if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
386 return fn(c, a, n, offset);
387 error(Eperm);
388 break;
389 }
390
391 if((buf = malloc(n)) == nil)
392 error(Enomem);
393 p = buf;
394 n = n/Linelen;
395 offset = offset/Linelen;
396
397 lock(&iomap);
398 for(map = iomap.map; n > 0 && map != nil; map = map->next){
399 if(offset-- > 0)
400 continue;
401 sprint(p, "%#8lux %#8lux %-12.12s\n", map->start, map->end-1, map->tag);
402 p += Linelen;
403 n--;
404 }
405 unlock(&iomap);
406
407 n = p - buf;
408 memmove(a, buf, n);
409 free(buf);
410
411 return n;
412 }
413
414 static long
archwrite(Chan * c,void * a,long n,vlong offset)415 archwrite(Chan *c, void *a, long n, vlong offset)
416 {
417 char *p;
418 int port;
419 ushort *sp;
420 ulong *lp;
421 Rdwrfn *fn;
422
423 switch((ulong)c->qid.path){
424
425 case Qiob:
426 p = a;
427 checkport(offset, offset+n);
428 for(port = offset; port < offset+n; port++)
429 outb(port, *p++);
430 return n;
431
432 case Qiow:
433 if(n & 1)
434 error(Ebadarg);
435 checkport(offset, offset+n);
436 sp = a;
437 for(port = offset; port < offset+n; port += 2)
438 outs(port, *sp++);
439 return n;
440
441 case Qiol:
442 if(n & 3)
443 error(Ebadarg);
444 checkport(offset, offset+n);
445 lp = a;
446 for(port = offset; port < offset+n; port += 4)
447 outl(port, *lp++);
448 return n;
449
450 default:
451 if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
452 return fn(c, a, n, offset);
453 error(Eperm);
454 break;
455 }
456 return 0;
457 }
458
459 Dev archdevtab = {
460 'P',
461 "arch",
462
463 devreset,
464 devinit,
465 devshutdown,
466 archattach,
467 archwalk,
468 archstat,
469 archopen,
470 devcreate,
471 archclose,
472 archread,
473 devbread,
474 archwrite,
475 devbwrite,
476 devremove,
477 devwstat,
478 };
479
480 /*
481 */
482 void
nop(void)483 nop(void)
484 {
485 }
486
487 void (*coherence)(void) = mfence;
488
489 static long
cputyperead(Chan *,void * a,long n,vlong off)490 cputyperead(Chan*, void *a, long n, vlong off)
491 {
492 char str[32];
493
494 snprint(str, sizeof(str), "%s %ud\n", "AMD64", m->cpumhz);
495 return readstr(off, a, n, str);
496 }
497
498 void
archinit(void)499 archinit(void)
500 {
501 addarchfile("cputype", 0444, cputyperead, nil);
502 }
503
504 void
archreset(void)505 archreset(void)
506 {
507 int i;
508
509 /*
510 * And sometimes there is no keyboard...
511 *
512 * The reset register (0xcf9) is usually in one of the bridge
513 * chips. The actual location and sequence could be extracted from
514 * ACPI but why bother, this is the end of the line anyway.
515 print("Takes a licking and keeps on ticking...\n");
516 */
517 i = inb(0xcf9); /* ICHx reset control */
518 i &= 0x06;
519 outb(0xcf9, i|0x02); /* SYS_RST */
520 millidelay(1);
521 outb(0xcf9, i|0x06); /* RST_CPU transition */
522
523 for(;;)
524 pause();
525 }
526
527 /*
528 * return value and speed of timer
529 */
530 uvlong
fastticks(uvlong * hz)531 fastticks(uvlong* hz)
532 {
533 if(hz != nil)
534 *hz = m->cpuhz;
535 return rdtsc();
536 }
537
538 ulong
s(void)539 µs(void)
540 {
541 return fastticks2us(rdtsc());
542 }
543
544 /*
545 * set next timer interrupt
546 */
547 void
timerset(uvlong x)548 timerset(uvlong x)
549 {
550 extern void apictimerset(uvlong);
551
552 apictimerset(x);
553 }
554
555 void
cycles(uvlong * t)556 cycles(uvlong* t)
557 {
558 *t = rdtsc();
559 }
560
561 void
delay(int millisecs)562 delay(int millisecs)
563 {
564 u64int r, t;
565
566 if(millisecs <= 0)
567 millisecs = 1;
568 r = rdtsc();
569 for(t = r + m->cpumhz*1000ull*millisecs; r < t; r = rdtsc())
570 ;
571 }
572
573 /*
574 * performance measurement ticks. must be low overhead.
575 * doesn't have to count over a second.
576 */
577 ulong
perfticks(void)578 perfticks(void)
579 {
580 uvlong x;
581
582 // if(m->havetsc)
583 cycles(&x);
584 // else
585 // x = 0;
586 return x;
587 }
588