]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/zynq/mmu.c
devether: mux bridges, portable netconsole
[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         if((pa & PTEUNCACHED) == 0)
151                 pa |= L2CACHED;
152         e = &up->l1->va[L1RX(va)];
153         if((*e & 3) == 0){
154                 p = up->mmufree;
155                 if(p != nil)
156                         up->mmufree = p->next;
157                 else
158                         p = newpage(0, 0, 0);
159                 p->daddr = L1RX(va);
160                 p->next = up->mmuused;
161                 up->mmuused = p;
162                 s = splhi();
163                 l2p = p->pa;
164                 l2 = tmpmap(l2p);
165                 memset(l2, 0, BY2PG);
166                 coherence();
167                 e[0] = p->pa | L1PT;
168                 e[1] = e[0] + L2SZ;
169                 e[2] = e[1] + L2SZ;
170                 e[3] = e[2] + L2SZ;
171                 coherence();
172         }else{
173                 s = splhi();
174                 l2p = *e & ~(BY2PG - 1);
175                 l2 = tmpmap(l2p);
176         }
177         e = &l2[L2RX(va)];
178         old = *e;
179         *e = pa | L2VALID | L2USER | L2LOCAL;
180         tmpunmap(l2);
181         splx(s);
182         if((old & L2VALID) != 0)
183                 flushpg((void *) va);
184         if(pg->txtflush & (1<<m->machno)){
185                 cleandse((void *) va, (void *) (va + BY2PG));
186                 invalise((void *) va, (void *) (va + BY2PG));
187                 pg->txtflush &= ~(1<<m->machno);
188         }
189 }
190
191 void
192 checkmmu(uintptr, uintptr)
193 {
194 }
195
196 void
197 flushmmu(void)
198 {
199         int s;
200
201         s = splhi();
202         up->newtlb = 1;
203         mmuswitch(up);
204         splx(s);
205 }
206
207 void
208 mmurelease(Proc *proc)
209 {
210         Page *p, *n;
211
212         if(islo())
213                 panic("mmurelease: islo");
214         
215         l1switch(&m->l1, 0);
216         if(proc->kmaptable != nil){
217                 if(proc->l1 == nil)
218                         panic("mmurelease: no l1");
219                 if(decref(proc->kmaptable) != 0)
220                         panic("mmurelease: kmap ref %ld", proc->kmaptable->ref);
221                 if(proc->nkmap)
222                         panic("mmurelease: nkmap %d", proc->nkmap);
223                 if(PPN(proc->l1->va[L1X(KMAP)]) != proc->kmaptable->pa)
224                         panic("mmurelease: bad kmap l2 %#.8lux kmap %#.8lux", proc->l1->va[L1X(KMAP)], proc->kmaptable->pa);
225                 proc->l1->va[L1X(KMAP)] = 0;
226                 pagechainhead(proc->kmaptable);
227                 proc->kmaptable = nil;
228         }
229         if(proc->l1 != nil){
230                 l2free(proc);
231                 l1free(proc->l1);
232                 proc->l1 = nil;
233         }
234         for(p = proc->mmufree; p != nil; p = n){
235                 n = p->next;
236                 if(decref(p) != 0)
237                         panic("mmurelease: p->ref %ld", p->ref);
238                 pagechainhead(p);
239         }
240         if(proc->mmufree != nil)
241                 pagechaindone();
242         proc->mmufree = nil;
243 }
244
245 void
246 countpagerefs(ulong *, int)
247 {
248         print("countpagerefs\n");
249 }
250
251 uintptr
252 paddr(void *v)
253 {
254         if((uintptr)v >= KZERO)
255                 return (uintptr)v-KZERO;
256         if((uintptr)v >= VMAP)
257                 return ((uintptr)v & (BY2PG-1)) | PPN(((ulong*)VMAPL2)[(uintptr)v-VMAP >> PGSHIFT]);
258         panic("paddr: va=%#p pc=%#p", v, getcallerpc(&v));
259         return 0;
260 }
261
262 void *
263 kaddr(uintptr u)
264 {
265         if(u < (uintptr)-KZERO)
266                 return (void *)(u + KZERO);
267         if(u >= OCM_BASE)
268                 return (void *)(ocm + (u - OCM_BASE));
269         panic("kaddr: pa=%#p pc=%#p", u, getcallerpc(&u));
270         return nil;
271 }
272
273 uintptr
274 cankaddr(uintptr u)
275 {
276         if(u < (uintptr)-KZERO)
277                 return -KZERO - u;
278         if(u >= OCM_BASE)
279                 return -u;
280         return 0;
281 }
282
283 KMap *
284 kmap(Page *page)
285 {
286         ulong *e, *v;
287         int i, s;
288
289         if(cankaddr(page->pa))
290                 return (KMap*)KADDR(page->pa);
291         if(up == nil)
292                 panic("kmap: up=0 pc=%#.8lux", getcallerpc(&page));
293         if(up->l1 == nil)
294                 upallocl1();
295         if(up->nkmap < 0)
296                 panic("kmap %lud %s: nkmap=%d", up->pid, up->text, up->nkmap);
297         up->nkmap++;
298         e = &up->l1->va[L1X(KMAP)];
299         if((*e & 3) == 0){
300                 if(up->kmaptable != nil)
301                         panic("kmaptable != nil");
302                 up->kmaptable = newpage(0, 0, 0);
303                 s = splhi();
304                 v = tmpmap(up->kmaptable->pa);
305                 memset(v, 0, BY2PG);
306                 v[0] = page->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
307                 v[NKMAP] = up->kmaptable->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
308                 tmpunmap(v);
309                 splx(s);
310                 *e = up->kmaptable->pa | L1PT;
311                 coherence();
312                 return (KMap *) KMAP;
313         }
314         if(up->kmaptable == nil)
315                 panic("kmaptable == nil");
316         e = (ulong *) (KMAP + NKMAP * BY2PG);
317         for(i = 0; i < NKMAP; i++)
318                 if((e[i] & 3) == 0){
319                         e[i] = page->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
320                         coherence();
321                         return (KMap *) (KMAP + i * BY2PG);
322                 }
323         panic("out of kmap");
324         return nil;
325 }
326
327 void
328 kunmap(KMap *arg)
329 {
330         uintptr va;
331         ulong *e;
332         
333         va = (uintptr) arg;
334         if(va >= KZERO)
335                 return;
336         if(up->l1 == nil || (up->l1->va[L1X(KMAP)] & 3) == 0)
337                 panic("kunmap: no kmaps");
338         if(va < KMAP || va >= KMAP + NKMAP * BY2PG)
339                 panic("kunmap: bad address %#.8lux pc=%#p", va, getcallerpc(&arg));
340         e = (ulong *) (KMAP + NKMAP * BY2PG) + L2X(va);
341         if((*e & 3) == 0)
342                 panic("kunmap: not mapped %#.8lux pc=%#p", va, getcallerpc(&arg));
343         up->nkmap--;
344         if(up->nkmap < 0)
345                 panic("kunmap %lud %s: nkmap=%d", up->pid, up->text, up->nkmap);
346         *e = 0;
347         coherence();
348         flushpg((void *) va);
349 }
350
351 void *
352 tmpmap(ulong pa)
353 {
354         ulong *u, *ub, *ue;
355
356         if(islo())
357                 panic("tmpmap: islow %#p", getcallerpc(&pa));
358         if(cankaddr(pa))
359                 return KADDR(pa);
360         ub = (ulong *) TMAPL2(m->machno);
361         ue = ub + NL2;
362         for(u = ub; u < ue; u++)
363                 if((*u & 3) == 0){
364                         *u = pa | L2VALID | L2CACHED | L2KERRW;
365
366                         assert(m->l1.va[L1X(TMAP)] != 0);
367                         if(up != nil && up->l1 != nil)
368                                 up->l1->va[L1X(TMAP)] = m->l1.va[L1X(TMAP)];
369
370                         coherence();
371                         return (void *) ((u - ub) * BY2PG + TMAP);
372                 }
373         panic("tmpmap: full (pa=%#.8lux)", pa);
374         return nil;
375 }
376
377 void
378 tmpunmap(void *v)
379 {
380         ulong *u;
381
382         if(v >= (void*) KZERO)
383                 return;
384         if(v < (void*)TMAP || v >= (void*)(TMAP + TMAPSZ))
385                 panic("tmpunmap: invalid address (va=%#.8lux)", (uintptr) v);
386         u = (ulong *) TMAPL2(m->machno) + L2X(v);
387         if((*u & 3) == 0)
388                 panic("tmpunmap: double unmap (va=%#.8lux)", (uintptr) v);
389         *u = 0;
390         coherence();
391         flushpg(v);
392 }
393
394 void *
395 vmap(uintptr pa, ulong sz)
396 {
397         ulong np;
398         void *vr, *ve;
399         static ulong *vp = (ulong *) VMAPL2 + 1; /* first page is uart */
400         
401         if((pa & BY2PG - 1) != 0)
402                 panic("vmap: misaligned pa=%#.8lux", pa);
403         np = (sz + BY2PG - 1) >> PGSHIFT;
404         vr = (char*) VMAP + (vp - (ulong *)VMAPL2 << PGSHIFT);
405         ve = (ulong *) (VMAPL2 + VMAPL2SZ);
406         while(np-- != 0){
407                 if(vp == ve)
408                         panic("vmap: out of vmap space (pa=%#.8lux)", pa);
409                 *vp++ = pa | L2VALID | L2DEVICE | L2KERRW;
410                 pa += BY2PG;
411         }
412         coherence();
413         return vr;
414 }
415
416 /* nasty things happen when there are cache entries for uncached memory
417    so must make sure memory is not mapped ANYWHERE cached */
418 void*
419 ucalloc(ulong len)
420 {
421         static uchar *free = nil;
422         static Lock l;
423         uchar *va;
424
425         if(len == 0)
426                 panic("ualloc: len == 0");
427
428         ilock(&l);
429         if(free == nil)
430                 free = ocm + -OCM_BASE - BY2PG; /* last page is cpu1 bootstrap */
431         len = PGROUND(len);
432         free -= len;
433         if(free < ocm)
434                 panic("ualloc: out of uncached memory");
435         va = free;
436         iunlock(&l);
437
438         invaldse(va, va + len);
439         return (void*)va;
440 }