]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/sgi/mmu.c
devarch: restrict i/o port access to 64K, disallow msr 32-bit wrap arround (thanks...
[plan9front.git] / sys / src / 9 / sgi / 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        "ureg.h"
7
8 /*
9  *  tlb entry 0 is used only by mmuswitch() to set the current tlb pid.
10  *
11  *  It is apparently assumed that user tlb entries are not
12  *  overwritten during start-up, so ...
13  *  During system start-up (before up first becomes non-nil),
14  *  Kmap entries start at tlb index 1 and work their way up until
15  *  kmapinval() removes them.  They then restart at 1.  As long as there
16  *  are few kmap entries they will not pass tlbroff (the WIRED tlb entry
17  *  limit) and interfere with user tlb entries.
18  *  Once start-up is over, we combine the kernel and user tlb pools into one,
19  *  in the hope of making better use of the tlb on systems with small ones.
20  *
21  *  All invalidations of the tlb are via indexed entries.  The virtual
22  *  address used is always 'KZERO | (x<<(PGSHIFT+1) | currentpid' where
23  *  'x' is the index into the tlb.  This ensures that the current pid doesn't
24  *  change and that no two invalidated entries have matching virtual
25  *  addresses just in case SGI/MIPS ever makes a chip that cares (as
26  *  they keep threatening).  These entries should never be used in
27  *  lookups since accesses to KZERO addresses don't go through the tlb
28  *  (actually only true of KSEG0 and KSEG1; KSEG2 and KSEG3 do go
29  *  through the tlb).
30  */
31
32 #define TLBINVAL(x, pid) puttlbx(x, KZERO|((x)<<(PGSHIFT+1))|(pid), 0, 0, PGSZ)
33
34 enum {
35         Debugswitch     = 0,
36         Debughash       = 0,
37 };
38
39 static ulong ktime[8];          /* only for first 8 cpus */
40
41 void
42 tlbinit(void)
43 {
44         int i;
45
46         for(i=0; i<NTLB; i++)
47                 TLBINVAL(i, 0);
48 }
49
50 Lock    kmaplock;
51 KMap    kpte[KPTESIZE];
52 KMap*   kmapfree;
53
54 static int minfree = KPTESIZE;
55 static int lastfree;
56 static int tlbroff = TLBROFF;
57
58 static void
59 nfree(void)
60 {
61         int i;
62         KMap *k;
63
64         i = 0;
65         for(k=kmapfree; k; k=k->next)
66                 i++;
67         if(i<minfree){
68                 iprint("%d free\n", i);
69                 minfree = i;
70         }
71         lastfree = i;
72 }
73
74 void
75 kmapinit(void)
76 {
77         KMap *k, *klast;
78
79         lock(&kmaplock);
80         kmapfree = kpte;
81         klast = &kpte[KPTESIZE-1];
82         for(k=kpte; k<klast; k++)
83                 k->next = k+1;
84         k->next = 0;
85         unlock(&kmaplock);
86
87         m->ktlbnext = TLBOFF;
88 }
89
90 void
91 kmapdump(void)
92 {
93         int i;
94
95         for(i=0; i<KPTESIZE; i++)
96                 iprint("%d: %lud pc=%#lux\n", i, kpte[i].ref, kpte[i].pc);
97 }
98
99 static int
100 putktlb(KMap *k)
101 {
102         int x;
103         ulong virt;
104         ulong tlbent[3];
105
106         virt = k->virt & ~BY2PG | TLBPID(tlbvirt());
107         x = gettlbp(virt, tlbent);
108         if (!m->paststartup)
109                 if (up) {                       /* startup just ended? */
110                         tlbroff = 1;
111                         setwired(tlbroff);      /* share all-but-one entries */
112                         m->paststartup = 1;
113                 } else if (x < 0) {             /* no such entry? use next */
114                         x = m->ktlbnext++;
115                         if(m->ktlbnext >= tlbroff)
116                                 m->ktlbnext = TLBOFF;
117                 }
118         if (x < 0) x = getrandom();             /* no entry for va? overwrite random one */
119         puttlbx(x, virt, k->phys0, k->phys1, PGSZ);
120         m->ktlbx[x] = 1;
121         return x;
122 }
123
124 /*
125  *  Arrange that the KMap'd virtual address will hit the same
126  *  primary cache line as pg->va by making bits 14...12 of the
127  *  tag the same as virtual address.  These bits are the index
128  *  into the primary cache and are checked whenever accessing
129  *  the secondary cache through the primary.  Violation causes
130  *  a VCE trap.
131  */
132 KMap *
133 kmap(Page *pg)
134 {
135         int s, printed = 0;
136         ulong pte, virt;
137         KMap *k;
138
139         s = splhi();
140         lock(&kmaplock);
141
142         if(kmapfree == 0) {
143 retry:
144                 unlock(&kmaplock);
145                 kmapinval();            /* try and free some */
146                 lock(&kmaplock);
147                 if(kmapfree == 0){
148                         unlock(&kmaplock);
149                         splx(s);
150                         if(printed++ == 0){
151                         /* using iprint here we get mixed up with other prints */
152                                 print("%d KMAP RETRY %#lux ktime %ld %ld %ld %ld %ld %ld %ld %ld\n",
153                                         m->machno, getcallerpc(&pg),
154                                         ktime[0], ktime[1], ktime[2], ktime[3],
155                                         ktime[4], ktime[5], ktime[6], ktime[7]);
156                                 delay(200);
157                         }
158                         splhi();
159                         lock(&kmaplock);
160                         goto retry;
161                 }
162         }
163
164         k = kmapfree;
165         kmapfree = k->next;
166
167         k->pg = pg;
168         /*
169          * One for the allocation,
170          * One for kactive
171          */
172         k->pc = getcallerpc(&pg);
173         k->ref = 2;
174         k->konmach[m->machno] = m->kactive;
175         m->kactive = k;
176
177         virt = pg->va;
178         /* bits 14..12 form the secondary-cache virtual index */
179         virt &= PIDX;
180         virt |= KMAPADDR | ((k-kpte)<<KMAPSHIFT);
181
182         k->virt = virt;
183         pte = PPN(pg->pa)|PTECACHABILITY|PTEGLOBL|PTEWRITE|PTEVALID;
184         if(virt & BY2PG) {
185                 k->phys0 = PTEGLOBL | PTECACHABILITY;
186                 k->phys1 = pte;
187         }
188         else {
189                 k->phys0 = pte;
190                 k->phys1 = PTEGLOBL | PTECACHABILITY;
191         }
192
193         putktlb(k);
194         unlock(&kmaplock);
195
196         splx(s);
197         return k;
198 }
199
200 void
201 kunmap(KMap *k)
202 {
203         int s;
204
205         s = splhi();
206         if(decref(k) == 0) {
207                 k->virt = 0;
208                 k->phys0 = 0;
209                 k->phys1 = 0;
210                 k->pg = 0;
211
212                 lock(&kmaplock);
213                 k->next = kmapfree;
214                 kmapfree = k;
215 //nfree();
216                 unlock(&kmaplock);
217         }
218         splx(s);
219 }
220
221 void
222 kfault(Ureg *ur)                        /* called from trap() */
223 {
224         ulong index, addr;
225         KMap *k, *f;
226
227         addr = ur->badvaddr;
228         index = (addr & ~KSEGM) >> KMAPSHIFT;
229         if(index >= KPTESIZE)
230                 panic("kmapfault: va=%#lux", addr);
231
232         k = &kpte[index];
233         if(k->virt == 0)
234                 panic("kmapfault: unmapped %#lux", addr);
235
236         for(f = m->kactive; f; f = f->konmach[m->machno])
237                 if(f == k)
238                         break;
239         if(f == 0) {
240                 incref(k);
241                 k->konmach[m->machno] = m->kactive;
242                 m->kactive = k;
243         }
244         putktlb(k);
245 }
246
247 void
248 kmapinval(void)
249 {
250         int mno, i, curpid;
251         KMap *k, *next;
252         uchar *ktlbx;
253
254         if(m->machno < nelem(ktime))
255                 ktime[m->machno] = MACHP(0)->ticks;
256         if(m->kactive == 0)
257                 return;
258
259         curpid = PTEPID(TLBPID(tlbvirt()));
260         ktlbx = m->ktlbx;
261         for(i = 0; i < NTLB; i++, ktlbx++){
262                 if(*ktlbx == 0)
263                         continue;
264                 TLBINVAL(i, curpid);
265                 *ktlbx = 0;
266         }
267
268         mno = m->machno;
269         for(k = m->kactive; k; k = next) {
270                 next = k->konmach[mno];
271                 kunmap(k);
272         }
273
274         m->kactive = 0;
275         m->ktlbnext = TLBOFF;
276 }
277
278 /*
279  * Process must be splhi
280  */
281 static int
282 newtlbpid(Proc *p)
283 {
284         int i, s;
285         Proc **h;
286
287         i = m->lastpid;
288         h = m->pidproc;
289         for(s = 0; s < NTLBPID; s++) {
290                 i++;
291                 if(i >= NTLBPID)
292                         i = 1;
293                 if(h[i] == 0)
294                         break;
295         }
296
297         if(h[i])
298                 purgetlb(i);
299         if(h[i] != 0)
300                 panic("newtlb");
301
302         m->pidproc[i] = p;
303         p->pidonmach[m->machno] = i;
304         m->lastpid = i;
305
306         return i;
307 }
308
309 void
310 mmuswitch(Proc *p)
311 {
312         int tp;
313         static char lasttext[32];
314
315         if(Debugswitch && !p->kp){
316                 if(strncmp(lasttext, p->text, sizeof lasttext) != 0)
317                         iprint("[%s]", p->text);
318                 strncpy(lasttext, p->text, sizeof lasttext);
319         }
320
321         if(p->newtlb) {
322                 memset(p->pidonmach, 0, sizeof p->pidonmach);
323                 p->newtlb = 0;
324         }
325         tp = p->pidonmach[m->machno];
326         if(tp == 0)
327                 tp = newtlbpid(p);
328         puttlbx(0, KZERO|PTEPID(tp), 0, 0, PGSZ);
329 }
330
331 void
332 mmurelease(Proc *p)
333 {
334         memset(p->pidonmach, 0, sizeof p->pidonmach);
335 }
336
337
338 /* tlbvirt also has TLBPID() in its low byte as the asid */
339 static Softtlb*
340 putstlb(ulong tlbvirt, ulong tlbphys)
341 {
342         int odd;
343         Softtlb *entry;
344
345         /* identical calculation in l.s/utlbmiss */
346         entry = &m->stb[stlbhash(tlbvirt)];
347         odd = tlbvirt & BY2PG;          /* even/odd bit */
348         tlbvirt &= ~BY2PG;              /* zero even/odd bit */
349         if(entry->virt != tlbvirt) {    /* not my entry? overwrite it */
350                 if(entry->virt != 0) {
351                         m->hashcoll++;
352                         if (Debughash)
353                                 iprint("putstlb: hash collision: %#lx old virt "
354                                         "%#lux new virt %#lux page %#lux\n",
355                                         entry - m->stb, entry->virt, tlbvirt,
356                                         tlbvirt >> (PGSHIFT+1));
357                 }
358                 entry->virt = tlbvirt;
359                 entry->phys0 = 0;
360                 entry->phys1 = 0;
361         }
362
363         if(odd)
364                 entry->phys1 = tlbphys;
365         else
366                 entry->phys0 = tlbphys;
367
368         if(entry->phys0 == 0 && entry->phys1 == 0)
369                 entry->virt = 0;
370
371         return entry;
372 }
373
374 void
375 putmmu(ulong tlbvirt, ulong tlbphys, Page *pg)
376 {
377         short tp;
378         ulong tlbent[3];
379         Softtlb *entry;
380         int s, x;
381
382         s = splhi();
383         tp = up->pidonmach[m->machno];
384         if(tp == 0)
385                 tp = newtlbpid(up);
386
387         tlbvirt |= PTEPID(tp);
388         if((tlbphys & PTEALGMASK) != PTEUNCACHED) {
389                 tlbphys &= ~PTEALGMASK;
390                 tlbphys |= PTECACHABILITY;
391         }
392
393         entry = putstlb(tlbvirt, tlbphys);
394         x = gettlbp(tlbvirt, tlbent);
395         if(x < 0) x = getrandom();
396         puttlbx(x, entry->virt, entry->phys0, entry->phys1, PGSZ);
397         if(pg->txtflush & (1<<m->machno)){
398                 icflush((void*)pg->va, BY2PG);
399                 pg->txtflush &= ~(1<<m->machno);
400         }
401         splx(s);
402 }
403
404 void
405 purgetlb(int pid)
406 {
407         int i, mno;
408         Proc *sp, **pidproc;
409         Softtlb *entry, *etab;
410
411         m->tlbpurge++;
412
413         /*
414          * find all pid entries that are no longer used by processes
415          */
416         mno = m->machno;
417         pidproc = m->pidproc;
418         for(i=1; i<NTLBPID; i++) {
419                 sp = pidproc[i];
420                 if(sp && sp->pidonmach[mno] != i)
421                         pidproc[i] = 0;
422         }
423
424         /*
425          * shoot down the one we want
426          */
427         sp = pidproc[pid];
428         if(sp != 0)
429                 sp->pidonmach[mno] = 0;
430         pidproc[pid] = 0;
431
432         /*
433          * clean out all dead pids from the stlb;
434          */
435         entry = m->stb;
436         for(etab = &entry[STLBSIZE]; entry < etab; entry++)
437                 if(pidproc[TLBPID(entry->virt)] == 0)
438                         entry->virt = 0;
439
440         /*
441          * clean up the hardware
442          */
443         for(i=tlbroff; i<NTLB; i++)
444                 if(pidproc[TLBPID(gettlbvirt(i))] == 0)
445                         TLBINVAL(i, pid);
446 }
447
448 void
449 flushmmu(void)
450 {
451         int s;
452
453         s = splhi();
454         up->newtlb = 1;
455         mmuswitch(up);
456         splx(s);
457 }
458
459 void
460 checkmmu(ulong, ulong)
461 {
462 }
463
464 void
465 countpagerefs(ulong*, int)
466 {
467 }
468
469 /*
470  * Return the number of bytes that can be accessed via KADDR(pa).
471  * If pa is not a valid argument to KADDR, return 0.
472  */
473 ulong
474 cankaddr(ulong pa)
475 {
476         if(pa >= KZERO)
477                 return 0;
478         return -KZERO - pa;
479 }