]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ppc/mmu.c
devip: cleanup rudp.c
[plan9front.git] / sys / src / 9 / ppc / mmu.c
1 #include        <u.h>
2 #include        <ureg.h>
3 #include        "../port/lib.h"
4 #include        "mem.h"
5 #include        "dat.h"
6 #include        "fns.h"
7
8 /*
9  *      We have one page table per processor.
10  *
11  *      Different processes are distinguished via the VSID field in
12  *      the segment registers.  As flushing the entire page table is an
13  *      expensive operation, we implement an aging algorithm for
14  *      mmu pids, with a background kproc to purge stale pids en mass.
15  *
16  *      This needs modifications to run on a multiprocessor.
17  */
18
19 static ulong    ptabsize;                       /* number of bytes in page table */
20 static ulong    ptabmask;               /* hash mask */
21
22 /*
23  *      VSID is 24 bits.  3 are required to distinguish segments in user
24  *      space (kernel space only uses the BATs).  pid 0 is reserved.
25  *      The top 2 bits of the pid are used as a `color' for the background
26  *      pid reclamation algorithm.
27  */
28
29 enum {
30         PIDBASE = 1,
31         PIDBITS = 21,
32         COLBITS = 2,
33         PIDMAX = ((1<<PIDBITS)-1),
34         COLMASK = ((1<<COLBITS)-1),
35 };
36
37 #define VSID(pid, i)    (((pid)<<3)|i)
38 #define PIDCOLOR(pid)   ((pid)>>(PIDBITS-COLBITS))
39 #define PTECOL(color)   PTE0(1, VSID(((color)<<(PIDBITS-COLBITS)), 0), 0, 0)
40
41 void
42 mmuinit(void)
43 {
44         int lhash, mem, i;
45         ulong memsize;
46
47         memsize = conf.npage * BY2PG;
48         if(ptabsize == 0) {
49                 /* heuristically size the hash table */
50                 lhash = 10;
51                 mem = (1<<23);
52                 while(mem < memsize) {
53                         lhash++;
54                         mem <<= 1;
55                 }
56                 ptabsize = (1<<(lhash+6));
57                 ptabmask = (1<<lhash)-1;
58         }
59         m->ptabbase = (ulong)xspanalloc(ptabsize, 0, ptabsize);
60         /* set page table base address */
61         putsdr1(PADDR(m->ptabbase) | (ptabmask>>10));
62         m->mmupid = PIDBASE;
63         m->sweepcolor = 0;
64         m->trigcolor = COLMASK;
65
66         for(i = 0; i < 16; i++)
67                 putsr(i<<28, 0);
68 }
69
70 static int
71 work(void*)
72 {
73         return PIDCOLOR(m->mmupid) == m->trigcolor;
74 }
75
76 void
77 mmusweep(void*)
78 {
79         Proc *p;
80         int i, x, sweepcolor;
81         ulong *ptab, *ptabend, ptecol;
82
83         while(waserror())
84                 ;
85
86         for(;;) {
87                 if(PIDCOLOR(m->mmupid) != m->trigcolor)
88                         sleep(&m->sweepr, work, nil);
89
90                 sweepcolor = m->sweepcolor;
91                 x = splhi();
92                 p = proctab(0);
93                 for(i = 0; i < conf.nproc; i++, p++)
94                         if(PIDCOLOR(p->mmupid) == sweepcolor)
95                                 p->mmupid = 0;
96                 splx(x);
97
98                 ptab = (ulong*)m->ptabbase;
99                 ptabend = (ulong*)(m->ptabbase+ptabsize);
100                 ptecol = PTECOL(sweepcolor);
101                 while(ptab < ptabend) {
102                         if((*ptab & PTECOL(3)) == ptecol){
103                                 *ptab = 0;
104                         }
105                         ptab += 2;
106                 }
107
108                 m->sweepcolor = (sweepcolor+1) & COLMASK;
109                 m->trigcolor = (m->trigcolor+1) & COLMASK;
110         }
111 }
112
113 int
114 newmmupid(void)
115 {
116         int pid, newcolor, i, x;
117         Proc *p;
118
119         pid = m->mmupid++;
120         if(m->mmupid > PIDMAX){
121                 /* Used up all mmupids, start again from first.  Flush the tlb
122                  * to delete any entries with old pids remaining, then reassign
123                  * all pids.
124                  */
125                 m->mmupid = PIDBASE;
126                 x = splhi();
127                 tlbflushall();
128                 p = proctab(0);
129                 for(i = 0; i < conf.nproc; i++, p++)
130                         p->mmupid = 0;
131                 splx(x);
132                 wakeup(&m->sweepr);
133         }
134         newcolor = PIDCOLOR(m->mmupid);
135         if(newcolor != PIDCOLOR(pid)) {
136                 if(newcolor == m->sweepcolor) {
137                         /* desperation time.  can't block here.  punt to fault/putmmu */
138                         print("newmmupid: %uld: no free mmu pids\n", up->pid);
139                         if(m->mmupid == PIDBASE)
140                                 m->mmupid = PIDMAX;
141                         else
142                                 m->mmupid--;
143                         pid = 0;
144                 }
145                 else if(newcolor == m->trigcolor)
146                         wakeup(&m->sweepr);
147         }
148         up->mmupid = pid;
149         return pid;
150 }
151
152 void
153 flushmmu(void)
154 {
155         int x;
156
157         x = splhi();
158         up->newtlb = 1;
159         mmuswitch(up);
160         splx(x);
161 }
162
163 /*
164  * called with splhi
165  */
166 void
167 mmuswitch(Proc *p)
168 {
169         int i, mp;
170         ulong r;
171
172         if(p->kp) {
173                 for(i = 0; i < 8; i++)
174                         putsr(i<<28, 0);
175                 return;
176         }
177
178         if(p->newtlb) {
179                 p->mmupid = 0;
180                 p->newtlb = 0;
181         }
182         mp = p->mmupid;
183         if(mp == 0)
184                 mp = newmmupid();
185
186         for(i = 0; i < 8; i++){
187                 r = VSID(mp, i)|BIT(1)|BIT(2);
188                 putsr(i<<28, r);
189         }
190 }
191
192 void
193 mmurelease(Proc* p)
194 {
195         p->mmupid = 0;
196 }
197
198 void
199 putmmu(uintptr va, uintptr pa, Page *pg)
200 {
201         int mp;
202         ulong *p, *ep, *q, pteg;
203         ulong vsid, hash;
204         ulong ptehi, x;
205         static ulong pva;
206
207         /*
208          *      If mmupid is 0, mmuswitch/newmmupid was unable to assign us
209          *      a pid, hence we faulted.  Keep calling sched() until the mmusweep
210          *      proc catches up, and we are able to get a pid.
211          */
212         while((mp = up->mmupid) == 0)
213                 sched();
214
215         vsid = VSID(mp, va>>28);
216         hash = (vsid ^ ((va>>12)&0xffff)) & ptabmask;
217         ptehi = PTE0(1, vsid, 0, va);
218         pteg = m->ptabbase + BY2PTEG*hash;
219
220         p = (ulong*)pteg;
221         ep = (ulong*)(pteg+BY2PTEG);
222         q = nil;
223
224         while(p < ep) {
225                 x = p[0];
226                 if(x == ptehi) {
227                         q = p;
228                         break;
229                 }
230                 if(q == nil && (x & BIT(0)) == 0)
231                         q = p;
232                 p += 2;
233         }
234         if(q == nil) {
235                 q = (ulong*)(pteg+m->slotgen);
236                 m->slotgen = (m->slotgen + BY2PTE) & (BY2PTEG-1);
237         }
238
239         if (q[0] != ptehi || q[1] != pa){
240                 tlbflush(va);
241                 m->tlbpurge++;
242         }
243         q[0] = ptehi;
244         q[1] = pa;
245
246         if(pg->txtflush & (1<<m->machno)){
247                 dcflush((void*)pg->va, BY2PG);
248                 icflush((void*)pg->va, BY2PG);
249                 pg->txtflush &= ~(1<<m->machno);
250         }
251 }
252
253 void
254 checkmmu(uintptr, uintptr)
255 {
256 }
257
258 void
259 countpagerefs(ulong*, int)
260 {
261 }
262
263 /*
264  * Return the number of bytes that can be accessed via KADDR(pa).
265  * If pa is not a valid argument to KADDR, return 0.
266  */
267 ulong
268 cankaddr(ulong pa)
269 {
270         if(pa >= -KZERO)
271                 return 0;
272         return -KZERO - pa;
273 }
274