|
|
1.1 root 1: /* vm_machdep.c 6.1 83/07/29 */
2:
3: #include "../machine/pte.h"
4:
5: #include "../h/param.h"
6: #include "../h/systm.h"
7: #include "../h/dir.h"
8: #include "../h/user.h"
9: #include "../h/proc.h"
10: #include "../h/cmap.h"
11: #include "../h/mount.h"
12: #include "../h/vm.h"
13: #include "../h/text.h"
14:
15: #include "../machine/mtpr.h"
16:
17: /*
18: * Set a red zone in the kernel stack after the u. area.
19: */
20: setredzone(pte, vaddr)
21: register struct pte *pte;
22: caddr_t vaddr;
23: {
24:
25: pte += (sizeof (struct user) + NBPG - 1) / NBPG;
26: *(int *)pte &= ~PG_PROT;
27: *(int *)pte |= PG_URKR;
28: if (vaddr)
29: mtpr(vaddr + sizeof (struct user) + NBPG - 1, TBIS);
30: }
31:
32: #ifndef mapin
33: mapin(pte, v, pfnum, count, prot)
34: struct pte *pte;
35: u_int v, pfnum;
36: int count, prot;
37: {
38:
39: while (count > 0) {
40: *(int *)pte++ = pfnum | prot;
41: mtpr(ptob(v), TBIS);
42: v++;
43: pfnum++;
44: count--;
45: }
46: }
47: #endif
48:
49: #ifdef notdef
50: /*ARGSUSED*/
51: mapout(pte, size)
52: register struct pte *pte;
53: int size;
54: {
55:
56: panic("mapout");
57: }
58: #endif
59:
60: /*
61: * Check for valid program size
62: */
63: chksize(ts, ds, ss)
64: register unsigned ts, ds, ss;
65: {
66: static int maxdmap = 0;
67:
68: if (ts > MAXTSIZ || ds > MAXDSIZ || ss > MAXSSIZ) {
69: u.u_error = ENOMEM;
70: return (1);
71: }
72: /* check for swap map overflow */
73: if (maxdmap == 0) {
74: register int i, blk;
75:
76: blk = dmmin;
77: for (i = 0; i < NDMAP; i++) {
78: maxdmap += blk;
79: if (blk < dmmax)
80: blk *= 2;
81: }
82: }
83: if (ctod(ts) > NXDAD * dmtext ||
84: ctod(ds) > maxdmap || ctod(ss) > maxdmap) {
85: u.u_error = ENOMEM;
86: return (1);
87: }
88: /*
89: * Make sure the process isn't bigger than our
90: * virtual memory limit.
91: *
92: * THERE SHOULD BE A CONSTANT FOR THIS.
93: */
94: if (ts + ds + ss + LOWPAGES + HIGHPAGES > btoc(USRSTACK)) {
95: u.u_error = ENOMEM;
96: return (1);
97: }
98: return (0);
99: }
100:
101: /*ARGSUSED*/
102: newptes(pte, v, size)
103: register struct pte *pte;
104: u_int v;
105: register int size;
106: {
107: register caddr_t a = ptob(v);
108:
109: #ifdef lint
110: pte = pte;
111: #endif
112: if (size >= 8) {
113: mtpr(0, TBIA);
114: return;
115: }
116: while (size > 0) {
117: mtpr(a, TBIS);
118: a += NBPG;
119: size--;
120: }
121: }
122:
123: /*
124: * Change protection codes of text segment.
125: * Have to flush translation buffer since this
126: * affect virtual memory mapping of current process.
127: */
128: chgprot(addr, tprot)
129: caddr_t addr;
130: long tprot;
131: {
132: unsigned v;
133: int tp;
134: register struct pte *pte;
135: register struct cmap *c;
136:
137: v = clbase(btop(addr));
138: if (!isatsv(u.u_procp, v)) {
139: u.u_error = EFAULT;
140: return (0);
141: }
142: tp = vtotp(u.u_procp, v);
143: pte = tptopte(u.u_procp, tp);
144: if (pte->pg_fod == 0 && pte->pg_pfnum) {
145: c = &cmap[pgtocm(pte->pg_pfnum)];
146: if (c->c_blkno && c->c_mdev != MSWAPX)
147: munhash(mount[c->c_mdev].m_dev,
148: (daddr_t)(u_long)c->c_blkno);
149: }
150: *(int *)pte &= ~PG_PROT;
151: *(int *)pte |= tprot;
152: distcl(pte);
153: tbiscl(v);
154: return (1);
155: }
156:
157: settprot(tprot)
158: long tprot;
159: {
160: register int *ptaddr, i;
161:
162: ptaddr = (int *)mfpr(P0BR);
163: for (i = 0; i < u.u_tsize; i++) {
164: ptaddr[i] &= ~PG_PROT;
165: ptaddr[i] |= tprot;
166: }
167: mtpr(0, TBIA);
168: }
169:
170: /*
171: * Rest are machine-dependent
172: */
173:
174: getmemc(addr)
175: caddr_t addr;
176: {
177: register int c;
178: struct pte savemap;
179:
180: savemap = mmap[0];
181: *(int *)mmap = PG_V | PG_KR | btop(addr);
182: mtpr(vmmap, TBIS);
183: uncache (&vmmap[(int)addr & PGOFSET]);
184: c = *(char *)&vmmap[(int)addr & PGOFSET];
185: mmap[0] = savemap;
186: mtpr(vmmap, TBIS);
187: return (c & 0377);
188: }
189:
190: putmemc(addr, val)
191: caddr_t addr;
192: {
193: struct pte savemap;
194:
195: savemap = mmap[0];
196: *(int *)mmap = PG_V | PG_KW | btop(addr);
197: mtpr(vmmap, TBIS);
198: *(char *)&vmmap[(int)addr & PGOFSET] = val;
199:
200: mtpr (0, PADC);
201: mtpr (0, PACC);
202:
203: mmap[0] = savemap;
204: mtpr(vmmap, TBIS);
205: }
206:
207: /*
208: * Move pages from one kernel virtual address to another.
209: * Both addresses are assumed to reside in the Sysmap,
210: * and size must be a multiple of CLSIZE.
211: */
212: pagemove(from, to, size)
213: register caddr_t from, to;
214: int size;
215: {
216: register struct pte *fpte, *tpte;
217:
218: if (size % CLBYTES)
219: panic("pagemove");
220: fpte = &Sysmap[btop(from - 0xC0000000)];
221: tpte = &Sysmap[btop(to - 0xC0000000)];
222: while (size > 0) {
223: *tpte++ = *fpte;
224: *(int *)fpte++ = 0;
225: mtpr(from, TBIS);
226: mtpr(to, TBIS);
227: mtpr(to, P1DC); /* purge !! */
228: from += NBPG;
229: to += NBPG;
230: size -= NBPG;
231: }
232: }
233:
234: /*
235: * Some code and data key management routines.
236: * The arrays ckey_cnt and ckey_cache are allways kept in such a way
237: * that the following invariant holds:
238: * (ckey_cnt > 0) ==> (ckey_cache == 1)
239: * meaning as long as a code key is used by at least one process, it's
240: * marked as being 'in the cache'. Of course, the following invariant
241: * also holds:
242: * (ckey_cache==0) ==> (ckey_cnt==0)
243: * which is just the reciprocal of the 1'st invariant.
244: * Equivalent invariants hold for the data key arrays.
245: */
246:
247:
248: int dbg_gck,
249: dbg_gck1,
250: dbg_gck2,
251: dbg_gck3,
252: dbg_gck4,
253: dbg_gdk,
254: dbg_gdk1,
255: dbg_gdk2,
256: dbg_gdk3;
257:
258: /*
259: * ckeyrelease -- release a code key.
260: */
261: ckeyrelease (key)
262: int key;
263: {
264: register int ipl;
265:
266: ipl = spl8();
267: if (--ckey_cnt[key] < 0) {
268: printf ("ckeyrelease: key = %d\n", key);
269: ckey_cnt[key] = 0;
270: }
271: splx (ipl);
272: }
273:
274:
275: /*
276: * dkeyrelease -- release a data key.
277: */
278: dkeyrelease (key)
279: int key;
280: {
281: register int ipl;
282:
283: ipl = spl8();
284: if (--dkey_cnt[key] != 0) {
285: printf ("dkeyrelease: key = %d\n", key);
286: dkey_cnt[key] = 0;
287: }
288: splx (ipl);
289: }
290:
291:
292: /*
293: * getcodekey -- get a code key.
294: */
295: getcodekey()
296: {
297: register int i,
298: ipl,
299: allocated, /* number of non-zero ckey_cnt's */
300: shared_key,
301: return_key;
302: register struct proc *p;
303:
304: dbg_gck++;
305:
306: ipl = spl8();
307: allocated = 0;
308:
309: for (i = 1; i <= MAXCKEY; i++) {
310: if ((int) ckey_cache[i] == 0) { /* Bingo */
311: ckey_cache[i] = 1;
312: ckey_cnt[i] = 1;
313: splx (ipl);
314: dbg_gck1++;
315: return (i);
316: }
317:
318: if (ckey_cnt[i] != 0)
319: allocated++;
320: if (ckey_cnt[i] > 1 && i != MAXCKEY)
321: shared_key = i;
322: }
323:
324: /*
325: * If we are here, all code keys were marked as being in cache.
326: * Moreover, we are assured that 'shared_key' has a meaningful value,
327: * since we know that the 'init' process and the 'shell' are around
328: * and they have shared text!
329: *
330: * Two cases: some of them are free for re-allocation, or all of
331: * them are currently allocated. In this (second) case, a more
332: * drastic procedure will follow - i.e. we strip some processes of
333: * their keys and let them get new ones whenever they need it.
334: */
335: if (allocated < MAXCKEY) {
336: /*
337: * This is the easy case.
338: */
339: for (i = 1; i <= MAXCKEY; i++) {
340: if (ckey_cnt[i] == 0) {
341: ckey_cache[i] = 0;
342: return_key = i;
343: }
344: }
345:
346: ckey_cnt[return_key] = 1;
347: ckey_cache[return_key] = 1;
348: mtpr (0, PACC);
349: splx (ipl);
350: dbg_gck2++;
351: return (return_key);
352: }
353:
354: /*
355: * Now we have to get nasty.
356: * Strip some of them of the code key. First time,
357: * 1) Try hard not to do that to kernel processes !!
358: * 2) Try hard NOT to strip shared text processes of
359: * their (shared) key, because then they'll run
360: * with different keys from now on, i.e. less efficient
361: * cache utilization.
362: */
363: for (p = proc; p < procNPROC; p++) {
364: /*
365: * Look for a meaningful key but not
366: * used and not shared text.
367: */
368: if (p->p_ckey && p->p_ckey!=MAXCKEY && ckey_cnt[p->p_ckey]<2) {
369: i = p->p_ckey;
370: p->p_ckey = 0;
371: ckey_cnt[i] = 1;
372: ckey_cache[i] = 1;
373: mtpr (0, PACC);
374: splx (ipl);
375: dbg_gck3++;
376: return (i);
377: }
378: }
379:
380: /*
381: * Second time around!
382: * Highly unlikely situation. It means that all keys are
383: * allocated AND shared (i.e. we have at least 510 active
384: * processes).
385: * Strip some of them. We pick some key (known to be shared
386: * by several processes) and strip the poor process group.
387: * At least 2 processes will loose but we gain one key to be reused.
388: * The way 'shared_key' was produced (above) virtually assures
389: * us that this key isn't the 'init' group key (1) nor the
390: * 'shell' group key (2 or 3). It's probably something like 254.
391: * Could be more straightforward to strip all processes, but it's
392: * better to invest in one more loop here and keep the cache
393: * utilization to a maximum.
394: */
395: for (p = proc; p < procNPROC; p++) {
396: if (p->p_ckey == shared_key) {
397: p->p_ckey = 0;
398: ckey_cnt[shared_key]--;
399: }
400: }
401:
402: if (ckey_cnt[shared_key] != 0)
403: printf("getcodekey: key = %d cnt = %d\n",
404: shared_key, ckey_cnt[shared_key]);
405:
406: ckey_cnt[shared_key] = 1;
407: ckey_cache[shared_key] = 1;
408: mtpr (0, PACC);
409: splx (ipl);
410: dbg_gck4++;
411: return (shared_key);
412: }
413:
414:
415: /*
416: * getdatakey -- get a data key.
417: *
418: * General strategy:
419: * 1) Try to find a data key that isn't in the cache. Allocate it.
420: * 2) If all data keys are in the cache, find one which isn't
421: * allocated. Clear all status and allocate this one.
422: * 3) If all of them are allocated, pick some process, strip him
423: * of the data key and allocate it. We (cold-bloodedly) pick
424: * one process to be the poor looser because that's the
425: * easiest way to do it and because this extreme situation
426: * ( >255 active processes ) is expected to be temporary,
427: * after which 1) or 2) above should be the usual case.
428: * The poor looser is the first process which has a data key.
429: * However, we try to spare known kernel processes and daemons
430: * (fired at bootstrap time), by searching from proc[LOOSER] and on.
431: */
432: getdatakey()
433: {
434: register int i,
435: ipl,
436: allocated, /* number of non-zero dkey_cnt's */
437: return_key;
438: register struct proc *p;
439:
440: #define LOOSER 20
441:
442: dbg_gdk++;
443:
444: ipl = spl8();
445: allocated = 0;
446: for (i = 1; i <= MAXDKEY; i++) {
447: if ((int) dkey_cache[i] == 0) {
448: /*
449: * Case 1. The best case.
450: */
451: dkey_cache[i] = 1;
452: dkey_cnt[i] = 1;
453: splx (ipl);
454: dbg_gdk1++;
455: return (i);
456: }
457: if (dkey_cnt[i] > 0)
458: allocated++;
459: }
460:
461: if (allocated < MAXDKEY) {
462: /*
463: * Case 2. This is the easy case.
464: */
465: for (i = 1; i <= MAXDKEY; i++) {
466: if (dkey_cnt[i] == 0) {
467: dkey_cache[i] = 0;
468: return_key = i;
469: }
470: }
471:
472: dkey_cnt[return_key] = 1;
473: dkey_cache[return_key] = 1;
474: mtpr (0, PADC);
475: splx (ipl);
476: dbg_gdk2++;
477: return (return_key);
478: }
479:
480: /*
481: * Now, we have to take a code from someone.
482: */
483: for (p = &proc[LOOSER]; p < procNPROC; p++) {
484: if (p->p_dkey != 0) {
485: i = p->p_dkey;
486: p->p_dkey = 0;
487: dkey_cnt[i] = 1;
488: dkey_cache[i] = 1;
489: mtpr (0, PADC);
490: splx (ipl);
491: dbg_gdk3++;
492: return (i);
493: }
494: }
495:
496: panic ("getdatakey");
497: }
498:
499:
500: /* General (includes system) virtual address to physical */
501: vtoph(p, v)
502: register struct proc *p;
503: register unsigned v;
504: {
505: register struct pte *thispte;
506:
507: thispte = vtopte (p, btop(v));
508: return ( (thispte->pg_pfnum << PGSHIFT) + (v & PGOFSET));
509: }
510:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.