]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ppc/mmu.c
pc/vga*: use 64-bit physical addresses and check pci membar types and sizes
[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                 for(i = 0; i < conf.nproc; i++){
93                         p = proctab(i);
94                         if(PIDCOLOR(p->mmupid) == sweepcolor)
95                                 p->mmupid = 0;
96                 }
97                 splx(x);
98
99                 ptab = (ulong*)m->ptabbase;
100                 ptabend = (ulong*)(m->ptabbase+ptabsize);
101                 ptecol = PTECOL(sweepcolor);
102                 while(ptab < ptabend) {
103                         if((*ptab & PTECOL(3)) == ptecol){
104                                 *ptab = 0;
105                         }
106                         ptab += 2;
107                 }
108
109                 m->sweepcolor = (sweepcolor+1) & COLMASK;
110                 m->trigcolor = (m->trigcolor+1) & COLMASK;
111         }
112 }
113
114 int
115 newmmupid(void)
116 {
117         int pid, newcolor, i, x;
118         Proc *p;
119
120         pid = m->mmupid++;
121         if(m->mmupid > PIDMAX){
122                 /* Used up all mmupids, start again from first.  Flush the tlb
123                  * to delete any entries with old pids remaining, then reassign
124                  * all pids.
125                  */
126                 m->mmupid = PIDBASE;
127                 x = splhi();
128                 tlbflushall();
129                 for(i = 0; i < conf.nproc; i++){
130                         p = proctab(i);
131                         p->mmupid = 0;
132                 }
133                 splx(x);
134                 wakeup(&m->sweepr);
135         }
136         newcolor = PIDCOLOR(m->mmupid);
137         if(newcolor != PIDCOLOR(pid)) {
138                 if(newcolor == m->sweepcolor) {
139                         /* desperation time.  can't block here.  punt to fault/putmmu */
140                         print("newmmupid: %uld: no free mmu pids\n", up->pid);
141                         if(m->mmupid == PIDBASE)
142                                 m->mmupid = PIDMAX;
143                         else
144                                 m->mmupid--;
145                         pid = 0;
146                 }
147                 else if(newcolor == m->trigcolor)
148                         wakeup(&m->sweepr);
149         }
150         up->mmupid = pid;
151         return pid;
152 }
153
154 void
155 flushmmu(void)
156 {
157         int x;
158
159         x = splhi();
160         up->newtlb = 1;
161         mmuswitch(up);
162         splx(x);
163 }
164
165 /*
166  * called with splhi
167  */
168 void
169 mmuswitch(Proc *p)
170 {
171         int i, mp;
172         ulong r;
173
174         if(p->kp) {
175                 for(i = 0; i < 8; i++)
176                         putsr(i<<28, 0);
177                 return;
178         }
179
180         if(p->newtlb) {
181                 p->mmupid = 0;
182                 p->newtlb = 0;
183         }
184         mp = p->mmupid;
185         if(mp == 0)
186                 mp = newmmupid();
187
188         for(i = 0; i < 8; i++){
189                 r = VSID(mp, i)|BIT(1)|BIT(2);
190                 putsr(i<<28, r);
191         }
192 }
193
194 void
195 mmurelease(Proc* p)
196 {
197         p->mmupid = 0;
198 }
199
200 void
201 putmmu(uintptr va, uintptr pa, Page *pg)
202 {
203         int mp;
204         ulong *p, *ep, *q, pteg;
205         ulong vsid, hash;
206         ulong ptehi, x;
207         static ulong pva;
208
209         /*
210          *      If mmupid is 0, mmuswitch/newmmupid was unable to assign us
211          *      a pid, hence we faulted.  Keep calling sched() until the mmusweep
212          *      proc catches up, and we are able to get a pid.
213          */
214         while((mp = up->mmupid) == 0)
215                 sched();
216
217         vsid = VSID(mp, va>>28);
218         hash = (vsid ^ ((va>>12)&0xffff)) & ptabmask;
219         ptehi = PTE0(1, vsid, 0, va);
220         pteg = m->ptabbase + BY2PTEG*hash;
221
222         p = (ulong*)pteg;
223         ep = (ulong*)(pteg+BY2PTEG);
224         q = nil;
225
226         while(p < ep) {
227                 x = p[0];
228                 if(x == ptehi) {
229                         q = p;
230                         break;
231                 }
232                 if(q == nil && (x & BIT(0)) == 0)
233                         q = p;
234                 p += 2;
235         }
236         if(q == nil) {
237                 q = (ulong*)(pteg+m->slotgen);
238                 m->slotgen = (m->slotgen + BY2PTE) & (BY2PTEG-1);
239         }
240
241         if (q[0] != ptehi || q[1] != pa){
242                 tlbflush(va);
243                 m->tlbpurge++;
244         }
245         q[0] = ptehi;
246         q[1] = pa;
247
248         if(pg->txtflush & (1<<m->machno)){
249                 dcflush((void*)pg->va, BY2PG);
250                 icflush((void*)pg->va, BY2PG);
251                 pg->txtflush &= ~(1<<m->machno);
252         }
253 }
254
255 void
256 checkmmu(uintptr, uintptr)
257 {
258 }
259
260 /*
261  * Return the number of bytes that can be accessed via KADDR(pa).
262  * If pa is not a valid argument to KADDR, return 0.
263  */
264 ulong
265 cankaddr(ulong pa)
266 {
267         if(pa >= -KZERO)
268                 return 0;
269         return -KZERO - pa;
270 }
271