merge in vnodes
[unix-history] / usr / src / sys / tahoe / tahoe / vm_machdep.c
CommitLineData
1c1b22c0
MK
1/*
2 * Copyright (c) 1988 Regents of the University of California.
677067f0 3 * All rights reserved.
1c1b22c0 4 *
677067f0
MK
5 * This code is derived from software contributed to Berkeley by
6 * Computer Consoles Inc.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
d09985e2 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
677067f0 19 *
d09985e2 20 * @(#)vm_machdep.c 7.3 (Berkeley) %G%
1c1b22c0 21 */
97f4d72d 22
a55e280b
SL
23#include "param.h"
24#include "systm.h"
a55e280b
SL
25#include "user.h"
26#include "proc.h"
27#include "cmap.h"
28#include "mount.h"
d09985e2 29#include "../ufs/ufsmount.h"
a55e280b
SL
30#include "vm.h"
31#include "text.h"
32#include "kernel.h"
97f4d72d 33
319e6566 34#include "pte.h"
37a669de
MK
35#include "cpu.h"
36#include "mtpr.h"
97f4d72d
SL
37
38/*
39 * Set a red zone in the kernel stack after the u. area.
40 */
41setredzone(pte, vaddr)
42 register struct pte *pte;
43 caddr_t vaddr;
44{
45
46 pte += (sizeof (struct user) + NBPG - 1) / NBPG;
47 *(int *)pte &= ~PG_PROT;
48 *(int *)pte |= PG_URKR;
49 if (vaddr)
a55e280b 50 mtpr(TBIS, vaddr + sizeof (struct user) + NBPG - 1);
97f4d72d
SL
51}
52
97f4d72d
SL
53/*
54 * Check for valid program size
56ad8000
SL
55 * NB - Check data and data growth separately as they may overflow
56 * when summed together.
97f4d72d 57 */
a55e280b
SL
58chksize(ts, ids, uds, ss)
59 register unsigned ts, ids, uds, ss;
97f4d72d 60{
9d61b7ff 61 extern unsigned maxtsize;
97f4d72d 62
56ad8000 63 if (ctob(ts) > maxtsize ||
a55e280b
SL
64 ctob(ids) > u.u_rlimit[RLIMIT_DATA].rlim_cur ||
65 ctob(uds) > u.u_rlimit[RLIMIT_DATA].rlim_cur ||
66 ctob(ids + uds) > u.u_rlimit[RLIMIT_DATA].rlim_cur ||
67 ctob(ss) > u.u_rlimit[RLIMIT_STACK].rlim_cur) {
97f4d72d
SL
68 u.u_error = ENOMEM;
69 return (1);
70 }
71 return (0);
72}
73
74/*ARGSUSED*/
75newptes(pte, v, size)
76 register struct pte *pte;
77 u_int v;
78 register int size;
79{
80 register caddr_t a = ptob(v);
81
82#ifdef lint
83 pte = pte;
84#endif
85 if (size >= 8) {
a55e280b 86 mtpr(TBIA, 0);
97f4d72d
SL
87 return;
88 }
89 while (size > 0) {
a55e280b 90 mtpr(TBIS, a);
97f4d72d
SL
91 a += NBPG;
92 size--;
93 }
94}
95
96/*
97 * Change protection codes of text segment.
98 * Have to flush translation buffer since this
99 * affect virtual memory mapping of current process.
100 */
101chgprot(addr, tprot)
102 caddr_t addr;
103 long tprot;
104{
105 unsigned v;
106 int tp;
107 register struct pte *pte;
108 register struct cmap *c;
109
110 v = clbase(btop(addr));
111 if (!isatsv(u.u_procp, v)) {
112 u.u_error = EFAULT;
113 return (0);
114 }
115 tp = vtotp(u.u_procp, v);
116 pte = tptopte(u.u_procp, tp);
117 if (pte->pg_fod == 0 && pte->pg_pfnum) {
118 c = &cmap[pgtocm(pte->pg_pfnum)];
119 if (c->c_blkno && c->c_mdev != MSWAPX)
d09985e2 120 munhash(mounttab[c->c_mdev].um_devvp,
97f4d72d
SL
121 (daddr_t)(u_long)c->c_blkno);
122 }
123 *(int *)pte &= ~PG_PROT;
124 *(int *)pte |= tprot;
125 distcl(pte);
126 tbiscl(v);
127 return (1);
128}
129
130settprot(tprot)
131 long tprot;
132{
133 register int *ptaddr, i;
134
135 ptaddr = (int *)mfpr(P0BR);
136 for (i = 0; i < u.u_tsize; i++) {
137 ptaddr[i] &= ~PG_PROT;
138 ptaddr[i] |= tprot;
139 }
a55e280b 140 mtpr(TBIA, 0);
97f4d72d
SL
141}
142
a55e280b 143#ifdef notdef
97f4d72d
SL
144/*
145 * Rest are machine-dependent
146 */
97f4d72d
SL
147getmemc(addr)
148 caddr_t addr;
149{
150 register int c;
151 struct pte savemap;
152
153 savemap = mmap[0];
154 *(int *)mmap = PG_V | PG_KR | btop(addr);
a55e280b
SL
155 mtpr(TBIS, vmmap);
156 uncache(&vmmap[(int)addr & PGOFSET]);
97f4d72d
SL
157 c = *(char *)&vmmap[(int)addr & PGOFSET];
158 mmap[0] = savemap;
a55e280b 159 mtpr(TBIS, vmmap);
97f4d72d
SL
160 return (c & 0377);
161}
162
163putmemc(addr, val)
164 caddr_t addr;
165{
166 struct pte savemap;
167
168 savemap = mmap[0];
169 *(int *)mmap = PG_V | PG_KW | btop(addr);
a55e280b 170 mtpr(TBIS, vmmap);
97f4d72d
SL
171 *(char *)&vmmap[(int)addr & PGOFSET] = val;
172
a55e280b
SL
173 mtpr(PADC, 0);
174 mtpr(PACC, 0);
97f4d72d
SL
175
176 mmap[0] = savemap;
a55e280b 177 mtpr(TBIS, vmmap);
97f4d72d 178}
a55e280b 179#endif
97f4d72d
SL
180
181/*
182 * Move pages from one kernel virtual address to another.
183 * Both addresses are assumed to reside in the Sysmap,
184 * and size must be a multiple of CLSIZE.
185 */
186pagemove(from, to, size)
187 register caddr_t from, to;
188 int size;
189{
190 register struct pte *fpte, *tpte;
191
192 if (size % CLBYTES)
193 panic("pagemove");
6585b458
MK
194 fpte = kvtopte(from);
195 tpte = kvtopte(to);
97f4d72d
SL
196 while (size > 0) {
197 *tpte++ = *fpte;
198 *(int *)fpte++ = 0;
a55e280b
SL
199 mtpr(TBIS, from);
200 mtpr(TBIS, to);
201 mtpr(P1DC, to); /* purge !! */
97f4d72d
SL
202 from += NBPG;
203 to += NBPG;
204 size -= NBPG;
205 }
206}
207
97f4d72d 208/*
a55e280b
SL
209 * Code and data key management routines.
210 *
37a669de
MK
211 * The array ckey_cnt maintains the count of processes currently
212 * sharing each code key. The array ckey_cache maintains a record
213 * of all code keys used since the last flush of the code cache.
214 * Such keys may not be reused, even if unreferenced, until
215 * the cache is flushed. The data cache key handling is analogous.
a55e280b
SL
216 * The arrays ckey_cnt and ckey_cache are allways kept in such a way
217 * that the following invariant holds:
218 * ckey_cnt > 0 =>'s ckey_cache == 1
219 * meaning as long as a code key is used by at least one process, it's
220 * marked as being 'in the cache'. Of course, the following invariant
221 * also holds:
222 * ckey_cache == 0 =>'s ckey_cnt == 0
223 * which is just the reciprocal of the 1'st invariant.
224 * Equivalent invariants hold for the data key arrays.
225 */
37a669de
MK
226struct keystats ckeystats = { NCKEY - 1 };
227struct keystats dkeystats = { NDKEY - 1 };
a55e280b
SL
228
229/*
230 * Release a code key.
231 */
232ckeyrelease(key)
233 int key;
234{
235 register int s;
236
237 s = spl8();
238 if (--ckey_cnt[key] < 0) {
239 printf("ckeyrelease: key = %d\n", key);
240 ckey_cnt[key] = 0;
97f4d72d 241 }
37a669de
MK
242 if (ckey_cnt[key] == 0)
243 ckeystats.ks_dirty++;
a55e280b 244 splx(s);
97f4d72d
SL
245}
246
97f4d72d 247/*
a55e280b 248 * Release a data key.
97f4d72d 249 */
a55e280b
SL
250dkeyrelease(key)
251 int key;
97f4d72d 252{
a55e280b
SL
253 register int s;
254
255 s = spl8();
256 if (--dkey_cnt[key] != 0) {
257 printf("dkeyrelease: key = %d\n", key);
258 dkey_cnt[key] = 0;
259 }
260 splx(s);
37a669de
MK
261 dkeystats.ks_dirty++;
262}
263
264/*
265 * Invalidate the data cache for a process
266 * by exchanging cache keys.
267 */
268dkeyinval(p)
269 register struct proc *p;
270{
37a669de
MK
271 int s;
272
273 dkeystats.ks_inval++;
274 s = spl8();
275 if (--dkey_cnt[p->p_dkey] != 0)
276 dkey_cnt[p->p_dkey] = 0;
319e6566 277 if (p == u.u_procp && !noproc) {
37a669de
MK
278 p->p_dkey = getdatakey();
279 mtpr(DCK, p->p_dkey);
280 } else
281 p->p_dkey = 0;
282 splx(s);
97f4d72d
SL
283}
284
97f4d72d 285/*
a55e280b 286 * Get a code key.
fbf82bb2
MK
287 * Strategy: try each of the following in turn
288 * until a key is allocated.
289 *
290 * 1) Find an unreferenced key not yet in the cache.
291 * If this fails, a code cache purge will be necessary.
292 * 2) Find an unreferenced key. Mark all unreferenced keys
293 * as available and purge the cache.
294 * 3) Free the keys from all processes not sharing keys.
295 * 4) Free the keys from all processes.
97f4d72d 296 */
a55e280b 297getcodekey()
97f4d72d 298{
37a669de 299 register int i, s, freekey;
a55e280b 300 register struct proc *p;
37a669de
MK
301 int desparate = 0;
302 static int lastkey = MAXCKEY;
a55e280b
SL
303
304 ckeystats.ks_allocs++;
305 s = spl8();
306 freekey = 0;
37a669de
MK
307 for (i = lastkey + 1; ; i++) {
308 if (i > MAXCKEY)
309 i = 1;
a55e280b
SL
310 if ((int)ckey_cache[i] == 0) { /* free key, take it */
311 ckey_cache[i] = 1, ckey_cnt[i] = 1;
312 splx(s);
37a669de
MK
313 ckeystats.ks_allocfree++;
314 ckeystats.ks_avail--;
315 lastkey = i;
a55e280b
SL
316 return (i);
317 }
37a669de
MK
318 if (ckey_cnt[i] == 0) /* save for potential use */
319 freekey = i;
320 if (i == lastkey)
321 break;
a55e280b
SL
322 }
323 /*
324 * All code keys were marked as being in cache.
a55e280b
SL
325 * If a key was in the cache, but not in use, grab it.
326 */
327 if (freekey != 0) {
37a669de 328purge:
a55e280b 329 /*
37a669de 330 * If we've run out of free keys,
a55e280b
SL
331 * try and free up some other keys to avoid
332 * future cache purges.
333 */
37a669de 334 ckey_cnt[freekey] = 1, ckey_cache[freekey] = 1;
a55e280b 335 for (i = 1; i <= MAXCKEY; i++)
37a669de 336 if (ckey_cnt[i] == 0) {
a55e280b 337 ckey_cache[i] = 0;
37a669de
MK
338 ckeystats.ks_avail++;
339 }
a55e280b
SL
340 mtpr(PACC, 0);
341 splx(s);
37a669de 342 ckeystats.ks_dirty = 0;
a55e280b
SL
343 ckeystats.ks_norefs++;
344 return (freekey);
97f4d72d 345 }
a55e280b
SL
346
347 /*
348 * All keys are marked as in the cache and in use.
fbf82bb2
MK
349 * Release all unshared keys, or, on second pass,
350 * release all keys.
a55e280b 351 */
37a669de
MK
352steal:
353 for (p = allproc; p; p = p->p_nxt)
354 if (p->p_ckey != 0 && (p->p_flag & SSYS) == 0) {
a55e280b 355 i = p->p_ckey;
37a669de 356 if (ckey_cnt[i] == 1 || desparate) {
fbf82bb2
MK
357 p->p_ckey = 0;
358 if (--ckey_cnt[i] == 0) {
37a669de 359 freekey = i;
37a669de
MK
360 if (p->p_textp)
361 p->p_textp->x_ckey = 0;
362 }
363 }
a55e280b
SL
364 }
365
37a669de
MK
366 if (freekey) {
367 ckeystats.ks_taken++;
368 goto purge;
369 } else {
370 desparate++;
371 goto steal;
97f4d72d 372 }
97f4d72d
SL
373}
374
97f4d72d 375/*
a55e280b
SL
376 * Get a data key.
377 *
378 * General strategy:
379 * 1) Try to find a data key that isn't in the cache. Allocate it.
380 * 2) If all data keys are in the cache, find one which isn't
fbf82bb2
MK
381 * allocated. Mark all unallocated keys as not in cache,
382 * purge the cache, and allocate this one.
383 * 3) If all of them are allocated, free all process' keys
37a669de 384 * and let them reclaim then as they run.
97f4d72d 385 */
a55e280b 386getdatakey()
97f4d72d 387{
37a669de 388 register int i, freekey;
a55e280b 389 register struct proc *p;
37a669de
MK
390 int s;
391 static int lastkey = MAXDKEY;
a55e280b
SL
392
393 dkeystats.ks_allocs++;
394 s = spl8();
395 freekey = 0;
37a669de
MK
396 for (i = lastkey + 1; ; i++) {
397 if (i > MAXDKEY)
398 i = 1;
a55e280b
SL
399 if ((int)dkey_cache[i] == 0) { /* free key, take it */
400 dkey_cache[i] = 1, dkey_cnt[i] = 1;
401 splx(s);
37a669de
MK
402 dkeystats.ks_allocfree++;
403 dkeystats.ks_avail--;
404 lastkey = i;
a55e280b
SL
405 return (i);
406 }
37a669de 407 if (dkey_cnt[i] == 0)
a55e280b 408 freekey = i;
37a669de
MK
409 if (i == lastkey)
410 break;
a55e280b 411 }
37a669de 412purge:
a55e280b
SL
413 if (freekey) {
414 /*
415 * Try and free up some more keys to avoid
416 * future allocations causing a cache purge.
417 */
a55e280b 418 dkey_cnt[freekey] = 1, dkey_cache[freekey] = 1;
37a669de
MK
419 for (i = 1; i <= MAXDKEY; i++)
420 if (dkey_cnt[i] == 0) {
421 dkey_cache[i] = 0;
422 dkeystats.ks_avail++;
423 }
a55e280b
SL
424 mtpr(PADC, 0);
425 splx(s);
426 dkeystats.ks_norefs++;
37a669de 427 dkeystats.ks_dirty = 0;
a55e280b 428 return (freekey);
97f4d72d 429 }
a55e280b
SL
430
431 /*
fbf82bb2 432 * Now, we have to take a key from someone.
37a669de
MK
433 * May as well take them all, so we get them
434 * from all of the idle procs.
a55e280b 435 */
37a669de
MK
436 for (p = allproc; p; p = p->p_nxt)
437 if (p->p_dkey != 0 && (p->p_flag & SSYS) == 0) {
438 freekey = p->p_dkey;
439 dkey_cnt[freekey] = 0;
a55e280b 440 p->p_dkey = 0;
a55e280b 441 }
37a669de
MK
442 dkeystats.ks_taken++;
443 goto purge;
97f4d72d 444}
97f4d72d 445
a55e280b 446/*VARGARGS1*/
97f4d72d 447vtoph(p, v)
a55e280b 448 register struct proc *p;
37a669de 449 unsigned v;
97f4d72d 450{
a55e280b 451 register struct pte *pte;
37a669de 452 register unsigned pg;
97f4d72d 453
37a669de
MK
454 pg = btop(v);
455 if (pg >= BTOPKERNBASE)
456 pte = &Sysmap[pg - BTOPKERNBASE];
457 else
458 pte = vtopte(p, pg);
a55e280b 459 return ((pte->pg_pfnum << PGSHIFT) + (v & PGOFSET));
97f4d72d 460}