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