]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/zynq/mmu.c
bootrc: allow kbmap to be set via plan9.ini (thanks Aaron Bieber)
[plan9front.git] / sys / src / 9 / zynq / mmu.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
8 ulong *mpcore, *slcr;
9 uchar *ocm;
10
11 void
12 mmuinit(void)
13 {
14         m->l1.pa = ttbget();
15         m->l1.va = KADDR(m->l1.pa);
16         memset((uchar*)TMAPL2(m->machno), 0, TMAPL2SZ);
17         m->l1.va[L1X(TMAP)] = PADDR(TMAPL2(m->machno)) | L1PT;
18         incref(&m->l1);
19         if(mpcore != nil)
20                 return;
21         mpcore = vmap(MPCORE_BASE, 0x2000);
22         slcr = vmap(SLCR_BASE, 0x1000);
23         ocm = vmap(OCM_BASE, -OCM_BASE);
24 }
25
26 void
27 l1switch(L1 *p, int flush)
28 {
29         assert(!islo());
30
31         ttbput(p->pa);
32         if(flush){
33                 if(++m->asid == 0)
34                         flushtlb();
35                 setasid(m->asid);
36         }
37 }
38
39 static L1 *
40 l1alloc(void)
41 {
42         L1 *p;
43         int s;
44
45         s = splhi();
46         p = m->l1free;
47         if(p != nil){
48                 m->l1free = p->next;
49                 p->next = nil;
50                 m->nfree--;
51                 splx(s);
52                 return p;
53         }
54         splx(s);
55         p = smalloc(sizeof(L1));
56         for(;;){
57                 p->va = mallocalign(L1SZ, L1SZ, 0, 0);
58                 if(p->va != nil)
59                         break;
60                 if(!waserror()){
61                         resrcwait("no memory for L1 table");
62                         poperror();
63                 }
64         }
65         p->pa = PADDR(p->va);
66         memmove(p->va, m->l1.va, L1SZ);
67         return p;
68 }
69
70 static void
71 l1free(L1 *l1)
72 {
73         if(islo())
74                 panic("l1free: islo");
75         if(m->nfree >= 40){
76                 free(l1->va);
77                 free(l1);
78         }else{
79                 l1->next = m->l1free;
80                 m->l1free = l1;
81                 m->nfree++;
82         }
83 }
84
85 static void
86 upallocl1(void)
87 {
88         L1 *p;
89         int s;
90
91         if(up->l1 != nil)
92                 return;
93         p = l1alloc();
94         s = splhi();
95         if(up->l1 != nil)
96                 panic("upalloc1: up->l1 != nil");
97         up->l1 = p;
98         l1switch(p, 1);
99         splx(s);
100 }
101
102 static void
103 l2free(Proc *proc)
104 {
105         ulong *t;
106         Page *p, **l;
107
108         if(proc->l1 == nil || proc->mmuused == nil)
109                 return;
110         l = &proc->mmuused;
111         for(p = *l; p != nil; p = p->next){
112                 t = proc->l1->va + p->daddr;
113                 *t++ = 0;
114                 *t++ = 0;
115                 *t++ = 0;
116                 *t = 0;
117                 l = &p->next;
118         }
119         proc->l1->va[L1X(TMAP)] = 0;
120         *l = proc->mmufree;
121         proc->mmufree = proc->mmuused;
122         proc->mmuused = 0;
123 }
124
125 void
126 mmuswitch(Proc *p)
127 {
128         if(p->newtlb){
129                 p->newtlb = 0;
130                 l2free(p);
131         }
132         if(p->l1 != nil)
133                 l1switch(p->l1, 1);
134         else
135                 l1switch(&m->l1, 1);
136 }
137
138 void
139 putmmu(uintptr va, uintptr pa, Page *pg)
140 {
141         Page *p;
142         ulong *e;
143         ulong *l2;
144         ulong old;
145         uintptr l2p;
146         int s;
147
148         if(up->l1 == nil)
149                 upallocl1();
150         e = &up->l1->va[L1RX(va)];
151         if((*e & 3) == 0){
152                 p = up->mmufree;
153                 if(p != nil)
154                         up->mmufree = p->next;
155                 else
156                         p = newpage(0, 0, 0);
157                 p->daddr = L1RX(va);
158                 p->next = up->mmuused;
159                 up->mmuused = p;
160                 s = splhi();
161                 l2p = p->pa;
162                 l2 = tmpmap(l2p);
163                 memset(l2, 0, BY2PG);
164                 coherence();
165                 e[0] = p->pa | L1PT;
166                 e[1] = e[0] + L2SZ;
167                 e[2] = e[1] + L2SZ;
168                 e[3] = e[2] + L2SZ;
169                 coherence();
170         }else{
171                 s = splhi();
172                 l2p = *e & ~(BY2PG - 1);
173                 l2 = tmpmap(l2p);
174         }
175         e = &l2[L2RX(va)];
176         old = *e;
177         *e = pa | L2VALID | L2USER | L2LOCAL;
178         tmpunmap(l2);
179         splx(s);
180         if((old & L2VALID) != 0)
181                 flushpg((void *) va);
182         if(pg->txtflush & (1<<m->machno)){
183                 cleandse((void *) va, (void *) (va + BY2PG));
184                 invalise((void *) va, (void *) (va + BY2PG));
185                 pg->txtflush &= ~(1<<m->machno);
186         }
187 }
188
189 void
190 checkmmu(uintptr, uintptr)
191 {
192 }
193
194 void
195 flushmmu(void)
196 {
197         int s;
198
199         s = splhi();
200         up->newtlb = 1;
201         mmuswitch(up);
202         splx(s);
203 }
204
205 void
206 mmurelease(Proc *proc)
207 {
208         Page *p, *n;
209
210         if(islo())
211                 panic("mmurelease: islo");
212         
213         l1switch(&m->l1, 0);
214         if(proc->kmaptable != nil){
215                 if(proc->l1 == nil)
216                         panic("mmurelease: no l1");
217                 if(decref(proc->kmaptable) != 0)
218                         panic("mmurelease: kmap ref %ld", proc->kmaptable->ref);
219                 if(proc->nkmap)
220                         panic("mmurelease: nkmap %d", proc->nkmap);
221                 if(PPN(proc->l1->va[L1X(KMAP)]) != proc->kmaptable->pa)
222                         panic("mmurelease: bad kmap l2 %#.8lux kmap %#.8lux", proc->l1->va[L1X(KMAP)], proc->kmaptable->pa);
223                 proc->l1->va[L1X(KMAP)] = 0;
224                 pagechainhead(proc->kmaptable);
225                 proc->kmaptable = nil;
226         }
227         if(proc->l1 != nil){
228                 l2free(proc);
229                 l1free(proc->l1);
230                 proc->l1 = nil;
231         }
232         for(p = proc->mmufree; p != nil; p = n){
233                 n = p->next;
234                 if(decref(p) != 0)
235                         panic("mmurelease: p->ref %ld", p->ref);
236                 pagechainhead(p);
237         }
238         if(proc->mmufree != nil)
239                 pagechaindone();
240         proc->mmufree = nil;
241 }
242
243 uintptr
244 paddr(void *v)
245 {
246         if((uintptr)v >= KZERO)
247                 return (uintptr)v-KZERO;
248         if((uintptr)v >= VMAP)
249                 return ((uintptr)v & (BY2PG-1)) | PPN(((ulong*)VMAPL2)[(uintptr)v-VMAP >> PGSHIFT]);
250         panic("paddr: va=%#p pc=%#p", v, getcallerpc(&v));
251         return 0;
252 }
253
254 void *
255 kaddr(uintptr u)
256 {
257         if(u < (uintptr)-KZERO)
258                 return (void *)(u + KZERO);
259         if(u >= OCM_BASE)
260                 return (void *)(ocm + (u - OCM_BASE));
261         panic("kaddr: pa=%#p pc=%#p", u, getcallerpc(&u));
262         return nil;
263 }
264
265 uintptr
266 cankaddr(uintptr u)
267 {
268         if(u < (uintptr)-KZERO)
269                 return -KZERO - u;
270         if(u >= OCM_BASE)
271                 return -u;
272         return 0;
273 }
274
275 KMap *
276 kmap(Page *page)
277 {
278         ulong *e, *v;
279         int i, s;
280
281         if(cankaddr(page->pa))
282                 return (KMap*)KADDR(page->pa);
283         if(up == nil)
284                 panic("kmap: up=0 pc=%#.8lux", getcallerpc(&page));
285         if(up->l1 == nil)
286                 upallocl1();
287         if(up->nkmap < 0)
288                 panic("kmap %lud %s: nkmap=%d", up->pid, up->text, up->nkmap);
289         up->nkmap++;
290         e = &up->l1->va[L1X(KMAP)];
291         if((*e & 3) == 0){
292                 if(up->kmaptable != nil)
293                         panic("kmaptable != nil");
294                 up->kmaptable = newpage(0, 0, 0);
295                 s = splhi();
296                 v = tmpmap(up->kmaptable->pa);
297                 memset(v, 0, BY2PG);
298                 v[0] = page->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
299                 v[NKMAP] = up->kmaptable->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
300                 tmpunmap(v);
301                 splx(s);
302                 *e = up->kmaptable->pa | L1PT;
303                 coherence();
304                 return (KMap *) KMAP;
305         }
306         if(up->kmaptable == nil)
307                 panic("kmaptable == nil");
308         e = (ulong *) (KMAP + NKMAP * BY2PG);
309         for(i = 0; i < NKMAP; i++)
310                 if((e[i] & 3) == 0){
311                         e[i] = page->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
312                         coherence();
313                         return (KMap *) (KMAP + i * BY2PG);
314                 }
315         panic("out of kmap");
316         return nil;
317 }
318
319 void
320 kunmap(KMap *arg)
321 {
322         uintptr va;
323         ulong *e;
324         
325         va = (uintptr) arg;
326         if(va >= KZERO)
327                 return;
328         if(up->l1 == nil || (up->l1->va[L1X(KMAP)] & 3) == 0)
329                 panic("kunmap: no kmaps");
330         if(va < KMAP || va >= KMAP + NKMAP * BY2PG)
331                 panic("kunmap: bad address %#.8lux pc=%#p", va, getcallerpc(&arg));
332         e = (ulong *) (KMAP + NKMAP * BY2PG) + L2X(va);
333         if((*e & 3) == 0)
334                 panic("kunmap: not mapped %#.8lux pc=%#p", va, getcallerpc(&arg));
335         up->nkmap--;
336         if(up->nkmap < 0)
337                 panic("kunmap %lud %s: nkmap=%d", up->pid, up->text, up->nkmap);
338         *e = 0;
339         coherence();
340         flushpg((void *) va);
341 }
342
343 void *
344 tmpmap(ulong pa)
345 {
346         ulong *u, *ub, *ue;
347
348         if(islo())
349                 panic("tmpmap: islow %#p", getcallerpc(&pa));
350         if(cankaddr(pa))
351                 return KADDR(pa);
352         ub = (ulong *) TMAPL2(m->machno);
353         ue = ub + NL2;
354         for(u = ub; u < ue; u++)
355                 if((*u & 3) == 0){
356                         *u = pa | L2VALID | L2CACHED | L2KERRW;
357
358                         assert(m->l1.va[L1X(TMAP)] != 0);
359                         if(up != nil && up->l1 != nil)
360                                 up->l1->va[L1X(TMAP)] = m->l1.va[L1X(TMAP)];
361
362                         coherence();
363                         return (void *) ((u - ub) * BY2PG + TMAP);
364                 }
365         panic("tmpmap: full (pa=%#.8lux)", pa);
366         return nil;
367 }
368
369 void
370 tmpunmap(void *v)
371 {
372         ulong *u;
373
374         if(v >= (void*) KZERO)
375                 return;
376         if(v < (void*)TMAP || v >= (void*)(TMAP + TMAPSZ))
377                 panic("tmpunmap: invalid address (va=%#.8lux)", (uintptr) v);
378         u = (ulong *) TMAPL2(m->machno) + L2X(v);
379         if((*u & 3) == 0)
380                 panic("tmpunmap: double unmap (va=%#.8lux)", (uintptr) v);
381         *u = 0;
382         coherence();
383         flushpg(v);
384 }
385
386 void *
387 vmap(uintptr pa, ulong sz)
388 {
389         ulong np;
390         void *vr, *ve;
391         static ulong *vp = (ulong *) VMAPL2 + 1; /* first page is uart */
392         
393         if((pa & BY2PG - 1) != 0)
394                 panic("vmap: misaligned pa=%#.8lux", pa);
395         np = (sz + BY2PG - 1) >> PGSHIFT;
396         vr = (char*) VMAP + (vp - (ulong *)VMAPL2 << PGSHIFT);
397         ve = (ulong *) (VMAPL2 + VMAPL2SZ);
398         while(np-- != 0){
399                 if(vp == ve)
400                         panic("vmap: out of vmap space (pa=%#.8lux)", pa);
401                 *vp++ = pa | L2VALID | L2DEVICE | L2NOEXEC | L2KERRW;
402                 pa += BY2PG;
403         }
404         coherence();
405         return vr;
406 }
407
408 /* nasty things happen when there are cache entries for uncached memory
409    so must make sure memory is not mapped ANYWHERE cached */
410 void*
411 ucalloc(ulong len)
412 {
413         static uchar *free = nil;
414         static Lock l;
415         uchar *va;
416
417         if(len == 0)
418                 panic("ualloc: len == 0");
419
420         ilock(&l);
421         if(free == nil)
422                 free = ocm + -OCM_BASE - BY2PG; /* last page is cpu1 bootstrap */
423         len = PGROUND(len);
424         free -= len;
425         if(free < ocm)
426                 panic("ualloc: out of uncached memory");
427         va = free;
428         iunlock(&l);
429
430         invaldse(va, va + len);
431         return (void*)va;
432 }