1458db832SDavid du Colombier #include <u.h>
2458db832SDavid du Colombier #include <ureg.h>
3458db832SDavid du Colombier #include "../port/lib.h"
4458db832SDavid du Colombier #include "mem.h"
5458db832SDavid du Colombier #include "dat.h"
6458db832SDavid du Colombier #include "fns.h"
7458db832SDavid du Colombier
8458db832SDavid du Colombier /*
9458db832SDavid du Colombier * We have one page table per processor.
10458db832SDavid du Colombier *
11458db832SDavid du Colombier * Different processes are distinguished via the VSID field in
12458db832SDavid du Colombier * the segment registers. As flushing the entire page table is an
13458db832SDavid du Colombier * expensive operation, we implement an aging algorithm for
14458db832SDavid du Colombier * mmu pids, with a background kproc to purge stale pids en mass.
15458db832SDavid du Colombier *
16458db832SDavid du Colombier * This needs modifications to run on a multiprocessor.
17458db832SDavid du Colombier */
18458db832SDavid du Colombier
19458db832SDavid du Colombier static ulong ptabsize; /* number of bytes in page table */
20458db832SDavid du Colombier static ulong ptabmask; /* hash mask */
21458db832SDavid du Colombier
22458db832SDavid du Colombier /*
23458db832SDavid du Colombier * VSID is 24 bits. 3 are required to distinguish segments in user
24458db832SDavid du Colombier * space (kernel space only uses the BATs). pid 0 is reserved.
25458db832SDavid du Colombier * The top 2 bits of the pid are used as a `color' for the background
26a6756dc4SDavid du Colombier * pid reclamation algorithm.
27458db832SDavid du Colombier */
28458db832SDavid du Colombier
29458db832SDavid du Colombier enum {
30458db832SDavid du Colombier PIDBASE = 1,
31458db832SDavid du Colombier PIDBITS = 21,
32458db832SDavid du Colombier COLBITS = 2,
33458db832SDavid du Colombier PIDMAX = ((1<<PIDBITS)-1),
34458db832SDavid du Colombier COLMASK = ((1<<COLBITS)-1),
35458db832SDavid du Colombier };
36458db832SDavid du Colombier
37458db832SDavid du Colombier #define VSID(pid, i) (((pid)<<3)|i)
38458db832SDavid du Colombier #define PIDCOLOR(pid) ((pid)>>(PIDBITS-COLBITS))
39458db832SDavid du Colombier #define PTECOL(color) PTE0(1, VSID(((color)<<(PIDBITS-COLBITS)), 0), 0, 0)
40458db832SDavid du Colombier
41458db832SDavid du Colombier void
mmuinit(void)42458db832SDavid du Colombier mmuinit(void)
43458db832SDavid du Colombier {
44458db832SDavid du Colombier int lhash, mem, i;
45458db832SDavid du Colombier ulong memsize;
46458db832SDavid du Colombier
47458db832SDavid du Colombier memsize = conf.npage * BY2PG;
48458db832SDavid du Colombier if(ptabsize == 0) {
49458db832SDavid du Colombier /* heuristically size the hash table */
50458db832SDavid du Colombier lhash = 10;
51458db832SDavid du Colombier mem = (1<<23);
52458db832SDavid du Colombier while(mem < memsize) {
53458db832SDavid du Colombier lhash++;
54458db832SDavid du Colombier mem <<= 1;
55458db832SDavid du Colombier }
56458db832SDavid du Colombier ptabsize = (1<<(lhash+6));
57458db832SDavid du Colombier ptabmask = (1<<lhash)-1;
58458db832SDavid du Colombier }
59458db832SDavid du Colombier m->ptabbase = (ulong)xspanalloc(ptabsize, 0, ptabsize);
60458db832SDavid du Colombier /* set page table base address */
61458db832SDavid du Colombier putsdr1(PADDR(m->ptabbase) | (ptabmask>>10));
62458db832SDavid du Colombier m->mmupid = PIDBASE;
63458db832SDavid du Colombier m->sweepcolor = 0;
64458db832SDavid du Colombier m->trigcolor = COLMASK;
65458db832SDavid du Colombier
66458db832SDavid du Colombier for(i = 0; i < 16; i++)
67458db832SDavid du Colombier putsr(i<<28, 0);
68458db832SDavid du Colombier }
69458db832SDavid du Colombier
70458db832SDavid du Colombier static int
work(void *)71458db832SDavid du Colombier work(void*)
72458db832SDavid du Colombier {
73458db832SDavid du Colombier return PIDCOLOR(m->mmupid) == m->trigcolor;
74458db832SDavid du Colombier }
75458db832SDavid du Colombier
76458db832SDavid du Colombier void
mmusweep(void *)77458db832SDavid du Colombier mmusweep(void*)
78458db832SDavid du Colombier {
79458db832SDavid du Colombier Proc *p;
80458db832SDavid du Colombier int i, x, sweepcolor;
81458db832SDavid du Colombier ulong *ptab, *ptabend, ptecol;
82458db832SDavid du Colombier
83458db832SDavid du Colombier for(;;) {
84458db832SDavid du Colombier if(PIDCOLOR(m->mmupid) != m->trigcolor)
85458db832SDavid du Colombier sleep(&m->sweepr, work, nil);
86458db832SDavid du Colombier
87458db832SDavid du Colombier sweepcolor = m->sweepcolor;
88458db832SDavid du Colombier x = splhi();
89458db832SDavid du Colombier p = proctab(0);
90458db832SDavid du Colombier for(i = 0; i < conf.nproc; i++, p++)
91458db832SDavid du Colombier if(PIDCOLOR(p->mmupid) == sweepcolor)
92458db832SDavid du Colombier p->mmupid = 0;
93458db832SDavid du Colombier splx(x);
94458db832SDavid du Colombier
95458db832SDavid du Colombier ptab = (ulong*)m->ptabbase;
96458db832SDavid du Colombier ptabend = (ulong*)(m->ptabbase+ptabsize);
97458db832SDavid du Colombier ptecol = PTECOL(sweepcolor);
98458db832SDavid du Colombier while(ptab < ptabend) {
99458db832SDavid du Colombier if((*ptab & PTECOL(3)) == ptecol){
100458db832SDavid du Colombier *ptab = 0;
101458db832SDavid du Colombier }
102458db832SDavid du Colombier ptab += 2;
103458db832SDavid du Colombier }
104458db832SDavid du Colombier
105458db832SDavid du Colombier m->sweepcolor = (sweepcolor+1) & COLMASK;
106458db832SDavid du Colombier m->trigcolor = (m->trigcolor+1) & COLMASK;
107458db832SDavid du Colombier }
108458db832SDavid du Colombier }
109458db832SDavid du Colombier
110458db832SDavid du Colombier int
newmmupid(void)111458db832SDavid du Colombier newmmupid(void)
112458db832SDavid du Colombier {
113458db832SDavid du Colombier int pid, newcolor, i, x;
114458db832SDavid du Colombier Proc *p;
115458db832SDavid du Colombier
116458db832SDavid du Colombier pid = m->mmupid++;
117458db832SDavid du Colombier if(m->mmupid > PIDMAX){
118458db832SDavid du Colombier /* Used up all mmupids, start again from first. Flush the tlb
119458db832SDavid du Colombier * to delete any entries with old pids remaining, then reassign
120458db832SDavid du Colombier * all pids.
121458db832SDavid du Colombier */
122458db832SDavid du Colombier m->mmupid = PIDBASE;
123458db832SDavid du Colombier x = splhi();
124458db832SDavid du Colombier tlbflushall();
125458db832SDavid du Colombier p = proctab(0);
126458db832SDavid du Colombier for(i = 0; i < conf.nproc; i++, p++)
127458db832SDavid du Colombier p->mmupid = 0;
128458db832SDavid du Colombier splx(x);
129458db832SDavid du Colombier wakeup(&m->sweepr);
130458db832SDavid du Colombier }
131458db832SDavid du Colombier newcolor = PIDCOLOR(m->mmupid);
132458db832SDavid du Colombier if(newcolor != PIDCOLOR(pid)) {
133458db832SDavid du Colombier if(newcolor == m->sweepcolor) {
134458db832SDavid du Colombier /* desperation time. can't block here. punt to fault/putmmu */
135458db832SDavid du Colombier print("newmmupid: %uld: no free mmu pids\n", up->pid);
136458db832SDavid du Colombier if(m->mmupid == PIDBASE)
137458db832SDavid du Colombier m->mmupid = PIDMAX;
138458db832SDavid du Colombier else
139458db832SDavid du Colombier m->mmupid--;
140458db832SDavid du Colombier pid = 0;
141458db832SDavid du Colombier }
142458db832SDavid du Colombier else if(newcolor == m->trigcolor)
143458db832SDavid du Colombier wakeup(&m->sweepr);
144458db832SDavid du Colombier }
145458db832SDavid du Colombier up->mmupid = pid;
146458db832SDavid du Colombier return pid;
147458db832SDavid du Colombier }
148458db832SDavid du Colombier
149458db832SDavid du Colombier void
flushmmu(void)150458db832SDavid du Colombier flushmmu(void)
151458db832SDavid du Colombier {
152458db832SDavid du Colombier int x;
153458db832SDavid du Colombier
154458db832SDavid du Colombier x = splhi();
155458db832SDavid du Colombier up->newtlb = 1;
156458db832SDavid du Colombier mmuswitch(up);
157458db832SDavid du Colombier splx(x);
158458db832SDavid du Colombier }
159458db832SDavid du Colombier
160458db832SDavid du Colombier /*
161458db832SDavid du Colombier * called with splhi
162458db832SDavid du Colombier */
163458db832SDavid du Colombier void
mmuswitch(Proc * p)164458db832SDavid du Colombier mmuswitch(Proc *p)
165458db832SDavid du Colombier {
166458db832SDavid du Colombier int i, mp;
167458db832SDavid du Colombier ulong r;
168458db832SDavid du Colombier
169458db832SDavid du Colombier if(p->kp) {
170458db832SDavid du Colombier for(i = 0; i < 8; i++)
171458db832SDavid du Colombier putsr(i<<28, 0);
172458db832SDavid du Colombier return;
173458db832SDavid du Colombier }
174458db832SDavid du Colombier
175458db832SDavid du Colombier if(p->newtlb) {
176458db832SDavid du Colombier p->mmupid = 0;
177458db832SDavid du Colombier p->newtlb = 0;
178458db832SDavid du Colombier }
179458db832SDavid du Colombier mp = p->mmupid;
180458db832SDavid du Colombier if(mp == 0)
181458db832SDavid du Colombier mp = newmmupid();
182458db832SDavid du Colombier
183458db832SDavid du Colombier for(i = 0; i < 8; i++){
184458db832SDavid du Colombier r = VSID(mp, i)|BIT(1)|BIT(2);
185458db832SDavid du Colombier putsr(i<<28, r);
186458db832SDavid du Colombier }
187458db832SDavid du Colombier }
188458db832SDavid du Colombier
189458db832SDavid du Colombier void
mmurelease(Proc * p)190458db832SDavid du Colombier mmurelease(Proc* p)
191458db832SDavid du Colombier {
192458db832SDavid du Colombier p->mmupid = 0;
193458db832SDavid du Colombier }
194458db832SDavid du Colombier
195458db832SDavid du Colombier void
putmmu(ulong va,ulong pa,Page * pg)196458db832SDavid du Colombier putmmu(ulong va, ulong pa, Page *pg)
197458db832SDavid du Colombier {
198458db832SDavid du Colombier int mp;
199458db832SDavid du Colombier char *ctl;
200458db832SDavid du Colombier ulong *p, *ep, *q, pteg;
201458db832SDavid du Colombier ulong vsid, hash;
202458db832SDavid du Colombier ulong ptehi, x;
203458db832SDavid du Colombier static ulong pva;
204458db832SDavid du Colombier
205458db832SDavid du Colombier /*
206458db832SDavid du Colombier * If mmupid is 0, mmuswitch/newmmupid was unable to assign us
207458db832SDavid du Colombier * a pid, hence we faulted. Keep calling sched() until the mmusweep
208458db832SDavid du Colombier * proc catches up, and we are able to get a pid.
209458db832SDavid du Colombier */
210458db832SDavid du Colombier while((mp = up->mmupid) == 0)
211458db832SDavid du Colombier sched();
212458db832SDavid du Colombier
213458db832SDavid du Colombier vsid = VSID(mp, va>>28);
214458db832SDavid du Colombier hash = (vsid ^ ((va>>12)&0xffff)) & ptabmask;
215458db832SDavid du Colombier ptehi = PTE0(1, vsid, 0, va);
216458db832SDavid du Colombier pteg = m->ptabbase + BY2PTEG*hash;
217458db832SDavid du Colombier
218458db832SDavid du Colombier p = (ulong*)pteg;
219458db832SDavid du Colombier ep = (ulong*)(pteg+BY2PTEG);
220458db832SDavid du Colombier q = nil;
221458db832SDavid du Colombier
222458db832SDavid du Colombier while(p < ep) {
223458db832SDavid du Colombier x = p[0];
224458db832SDavid du Colombier if(x == ptehi) {
225458db832SDavid du Colombier q = p;
226458db832SDavid du Colombier break;
227458db832SDavid du Colombier }
228458db832SDavid du Colombier if(q == nil && (x & BIT(0)) == 0)
229458db832SDavid du Colombier q = p;
230458db832SDavid du Colombier p += 2;
231458db832SDavid du Colombier }
232458db832SDavid du Colombier if(q == nil) {
233458db832SDavid du Colombier q = (ulong*)(pteg+m->slotgen);
234458db832SDavid du Colombier m->slotgen = (m->slotgen + BY2PTE) & (BY2PTEG-1);
235458db832SDavid du Colombier }
236458db832SDavid du Colombier
237458db832SDavid du Colombier if (q[0] != ptehi || q[1] != pa){
238458db832SDavid du Colombier tlbflush(va);
239458db832SDavid du Colombier m->tlbpurge++;
240458db832SDavid du Colombier }
241458db832SDavid du Colombier q[0] = ptehi;
242458db832SDavid du Colombier q[1] = pa;
243458db832SDavid du Colombier
244458db832SDavid du Colombier ctl = &pg->cachectl[m->machno];
245458db832SDavid du Colombier switch(*ctl) {
246458db832SDavid du Colombier case PG_NEWCOL:
247458db832SDavid du Colombier default:
248458db832SDavid du Colombier panic("putmmu: %d\n", *ctl);
249458db832SDavid du Colombier break;
250458db832SDavid du Colombier case PG_TXTFLUSH:
251458db832SDavid du Colombier dcflush((void*)pg->va, BY2PG);
252458db832SDavid du Colombier icflush((void*)pg->va, BY2PG);
253458db832SDavid du Colombier *ctl = PG_NOFLUSH;
254458db832SDavid du Colombier break;
255458db832SDavid du Colombier case PG_NOFLUSH:
256458db832SDavid du Colombier break;
257458db832SDavid du Colombier }
258458db832SDavid du Colombier
259458db832SDavid du Colombier }
260d717568cSDavid du Colombier
261ea15f0ccSDavid du Colombier void
checkmmu(ulong,ulong)262ea15f0ccSDavid du Colombier checkmmu(ulong, ulong)
263ea15f0ccSDavid du Colombier {
264ea15f0ccSDavid du Colombier }
265ea15f0ccSDavid du Colombier
266ea15f0ccSDavid du Colombier void
countpagerefs(ulong *,int)267ea15f0ccSDavid du Colombier countpagerefs(ulong*, int)
268ea15f0ccSDavid du Colombier {
269ea15f0ccSDavid du Colombier }
270*c717cbbdSDavid du Colombier
271*c717cbbdSDavid du Colombier /*
272*c717cbbdSDavid du Colombier * Return the number of bytes that can be accessed via KADDR(pa).
273*c717cbbdSDavid du Colombier * If pa is not a valid argument to KADDR, return 0.
274*c717cbbdSDavid du Colombier */
275*c717cbbdSDavid du Colombier ulong
cankaddr(ulong pa)276*c717cbbdSDavid du Colombier cankaddr(ulong pa)
277*c717cbbdSDavid du Colombier {
278*c717cbbdSDavid du Colombier if(pa >= -KZERO)
279*c717cbbdSDavid du Colombier return 0;
280*c717cbbdSDavid du Colombier return -KZERO - pa;
281*c717cbbdSDavid du Colombier }
282*c717cbbdSDavid du Colombier
283