Commit | Line | Data |
---|---|---|
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 | */ | |
41 | setredzone(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 |
58 | chksize(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*/ | |
75 | newptes(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 | */ | |
101 | chgprot(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 | ||
130 | settprot(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 |
147 | getmemc(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 | ||
163 | putmemc(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 | */ | |
186 | pagemove(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 |
226 | struct keystats ckeystats = { NCKEY - 1 }; |
227 | struct keystats dkeystats = { NDKEY - 1 }; | |
a55e280b SL |
228 | |
229 | /* | |
230 | * Release a code key. | |
231 | */ | |
232 | ckeyrelease(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 |
250 | dkeyrelease(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 | */ | |
268 | dkeyinval(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 | 297 | getcodekey() |
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 | 328 | purge: |
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 |
352 | steal: |
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 | 386 | getdatakey() |
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 | 412 | purge: |
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 | 447 | vtoph(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 | } |