]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/mtx/devarch.c
bcm64: set XN bits for kernel device mappings
[plan9front.git] / sys / src / 9 / mtx / devarch.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8
9 typedef struct IOMap IOMap;
10 struct IOMap
11 {
12         IOMap   *next;
13         char    tag[13];
14         ulong   start;
15         ulong   end;
16 };
17
18 static struct
19 {
20         Lock;
21         IOMap   *m;
22         IOMap   *free;
23         IOMap   maps[32];               // some initial free maps
24
25         QLock   ql;                     // lock for reading map
26 } iomap;
27
28 enum {
29         Qdir = 0,
30         Qioalloc = 1,
31         Qiob,
32         Qiow,
33         Qiol,
34         Qbase,
35
36         Qmax = 16,
37 };
38
39 typedef long Rdwrfn(Chan*, void*, long, vlong);
40
41 static Rdwrfn *readfn[Qmax];
42 static Rdwrfn *writefn[Qmax];
43
44 static Dirtab archdir[] = {
45         ".",    { Qdir, 0, QTDIR },     0,      0555,
46         "ioalloc",      { Qioalloc, 0 },        0,      0444,
47         "iob",          { Qiob, 0 },            0,      0660,
48         "iow",          { Qiow, 0 },            0,      0660,
49         "iol",          { Qiol, 0 },            0,      0660,
50 };
51 Lock archwlock; /* the lock is only for changing archdir */
52 int narchdir = Qbase;
53 int (*_pcmspecial)(char *, ISAConf *);
54 void (*_pcmspecialclose)(int);
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*
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
96 ioinit(void)
97 {
98         int i;
99
100         for(i = 0; i < nelem(iomap.maps)-1; i++)
101                 iomap.maps[i].next = &iomap.maps[i+1];
102         iomap.maps[i].next = nil;
103         iomap.free = iomap.maps;
104
105         // a dummy entry at 2^17
106         ioalloc(0x20000, 1, 0, "dummy");
107 }
108
109 //
110 //      alloc some io port space and remember who it was
111 //      alloced to.  if port < 0, find a free region.
112 //
113 int
114 ioalloc(int port, int size, int align, char *tag)
115 {
116         IOMap *m, **l;
117         int i;
118
119         lock(&iomap);
120         if(port < 0){
121                 // find a free port above 0x400 and below 0x1000
122                 port = 0x400;
123                 for(l = &iomap.m; *l; l = &(*l)->next){
124                         m = *l;
125                         i = m->start - port;
126                         if(i > size)
127                                 break;
128                         if(align > 0)
129                                 port = ((port+align-1)/align)*align;
130                         else
131                                 port = m->end;
132                 }
133                 if(*l == nil){
134                         unlock(&iomap);
135                         return -1;
136                 }
137         } else {
138                 // see if the space clashes with previously allocated ports
139                 for(l = &iomap.m; *l; l = &(*l)->next){
140                         m = *l;
141                         if(m->end <= port)
142                                 continue;
143                         if(m->start >= port+size)
144                                 break;
145                         unlock(&iomap);
146                         return -1;
147                 }
148         }
149         m = iomap.free;
150         if(m == nil){
151                 print("ioalloc: out of maps");
152                 unlock(&iomap);
153                 return port;
154         }
155         iomap.free = m->next;
156         m->next = *l;
157         m->start = port;
158         m->end = port + size;
159         strncpy(m->tag, tag, sizeof(m->tag));
160         m->tag[sizeof(m->tag)-1] = 0;
161         *l = m;
162
163         archdir[0].qid.vers++;
164
165         unlock(&iomap);
166         return m->start;
167 }
168
169 void
170 iofree(int port)
171 {
172         IOMap *m, **l;
173
174         lock(&iomap);
175         for(l = &iomap.m; *l; l = &(*l)->next){
176                 if((*l)->start == port){
177                         m = *l;
178                         *l = m->next;
179                         m->next = iomap.free;
180                         iomap.free = m;
181                         break;
182                 }
183                 if((*l)->start > port)
184                         break;
185         }
186         archdir[0].qid.vers++;
187         unlock(&iomap);
188 }
189
190 int
191 iounused(int start, int end)
192 {
193         IOMap *m;
194
195         for(m = iomap.m; m; m = m->next){
196                 if(start >= m->start && start < m->end
197                 || start <= m->start && end > m->start)
198                         return 0; 
199         }
200         return 1;
201 }
202
203 static void
204 checkport(int start, int end)
205 {
206         /* standard vga regs are OK */
207         if(start >= 0x2b0 && end <= 0x2df+1)
208                 return;
209         if(start >= 0x3c0 && end <= 0x3da+1)
210                 return;
211
212         if(iounused(start, end))
213                 return;
214         error(Eperm);
215 }
216
217 static Chan*
218 archattach(char* spec)
219 {
220         return devattach('P', spec);
221 }
222
223 Walkqid*
224 archwalk(Chan* c, Chan *nc, char** name, int nname)
225 {
226         return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
227 }
228
229 static int
230 archstat(Chan* c, uchar* dp, int n)
231 {
232         return devstat(c, dp, n, archdir, narchdir, devgen);
233 }
234
235 static Chan*
236 archopen(Chan* c, int omode)
237 {
238         return devopen(c, omode, archdir, nelem(archdir), devgen);
239 }
240
241 static void
242 archclose(Chan*)
243 {
244 }
245
246 enum
247 {
248         Linelen= 31,
249 };
250
251 static long
252 archread(Chan *c, void *a, long n, vlong offset)
253 {
254         char buf[Linelen+1], *p;
255         int port;
256         ushort *sp;
257         ulong *lp;
258         IOMap *m;
259         Rdwrfn *fn;
260
261         switch((ulong)c->qid.path){
262
263         case Qdir:
264                 return devdirread(c, a, n, archdir, nelem(archdir), devgen);
265
266         case Qiob:
267                 port = offset;
268                 checkport(offset, offset+n);
269                 for(p = a; port < offset+n; port++)
270                         *p++ = inb(port);
271                 return n;
272
273         case Qiow:
274                 if((n & 0x01) || (offset & 0x01))
275                         error(Ebadarg);
276                 checkport(offset, offset+n+1);
277                 n /= 2;
278                 sp = a;
279                 for(port = offset; port < offset+n; port += 2)
280                         *sp++ = ins(port);
281                 return n*2;
282
283         case Qiol:
284                 if((n & 0x03) || (offset & 0x03))
285                         error(Ebadarg);
286                 checkport(offset, offset+n+3);
287                 n /= 4;
288                 lp = a;
289                 for(port = offset; port < offset+n; port += 4)
290                         *lp++ = inl(port);
291                 return n*4;
292
293         case Qioalloc:
294                 break;
295
296         default:
297                 if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
298                         return fn(c, a, n, offset);
299                 error(Eperm);
300                 break;
301         }
302
303         offset = offset/Linelen;
304         n = n/Linelen;
305         p = a;
306         lock(&iomap);
307         for(m = iomap.m; n > 0 && m != nil; m = m->next){
308                 if(offset-- > 0)
309                         continue;
310                 if(strcmp(m->tag, "dummy") == 0)
311                         break;
312                 sprint(buf, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
313                 memmove(p, buf, Linelen);
314                 p += Linelen;
315                 n--;
316         }
317         unlock(&iomap);
318
319         return p - (char*)a;
320 }
321
322 static long
323 archwrite(Chan *c, void *a, long n, vlong offset)
324 {
325         char *p;
326         int port;
327         ushort *sp;
328         ulong *lp;
329         Rdwrfn *fn;
330
331         switch((ulong)c->qid.path){
332
333         case Qiob:
334                 p = a;
335                 checkport(offset, offset+n);
336                 for(port = offset; port < offset+n; port++)
337                         outb(port, *p++);
338                 return n;
339
340         case Qiow:
341                 if((n & 01) || (offset & 01))
342                         error(Ebadarg);
343                 checkport(offset, offset+n+1);
344                 n /= 2;
345                 sp = a;
346                 for(port = offset; port < offset+n; port += 2)
347                         outs(port, *sp++);
348                 return n*2;
349
350         case Qiol:
351                 if((n & 0x03) || (offset & 0x03))
352                         error(Ebadarg);
353                 checkport(offset, offset+n+3);
354                 n /= 4;
355                 lp = a;
356                 for(port = offset; port < offset+n; port += 4)
357                         outl(port, *lp++);
358                 return n*4;
359
360         default:
361                 if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
362                         return fn(c, a, n, offset);
363                 error(Eperm);
364                 break;
365         }
366         return 0;
367 }
368
369 Dev archdevtab = {
370         'P',
371         "arch",
372
373         devreset,
374         devinit,
375         devshutdown,
376         archattach,
377         archwalk,
378         archstat,
379         archopen,
380         devcreate,
381         archclose,
382         archread,
383         devbread,
384         archwrite,
385         devbwrite,
386         devremove,
387         devwstat,
388 };
389
390 int
391 pcmspecial(char *idstr, ISAConf *isa)
392 {
393         return (_pcmspecial  != nil)? _pcmspecial(idstr, isa): -1;
394 }
395
396 void
397 pcmspecialclose(int a)
398 {
399         if (_pcmspecialclose != nil)
400                 _pcmspecialclose(a);
401 }