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