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