|
|
1.1 root 1: /*
2: * Copyright (c) 1991 Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * The Mach Operating System project at Carnegie-Mellon University.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
1.1.1.4 ! root 36: * from: @(#)vm_glue.c 7.8 (Berkeley) 5/15/91
! 37: * vm_glue.c,v 1.10.2.1 1993/07/31 12:20:51 cgd Exp
1.1 root 38: *
39: *
40: * Copyright (c) 1987, 1990 Carnegie-Mellon University.
41: * All rights reserved.
42: *
43: * Permission to use, copy, modify and distribute this software and
44: * its documentation is hereby granted, provided that both the copyright
45: * notice and this permission notice appear in all copies of the
46: * software, derivative works or modified versions, and any portions
47: * thereof, and that both notices appear in supporting documentation.
48: *
49: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
50: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
51: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
52: *
53: * Carnegie Mellon requests users of this software to return to
54: *
55: * Software Distribution Coordinator or [email protected]
56: * School of Computer Science
57: * Carnegie Mellon University
58: * Pittsburgh PA 15213-3890
59: *
60: * any improvements or extensions that they make and grant Carnegie the
61: * rights to redistribute these changes.
62: */
63:
64: #include "param.h"
65: #include "systm.h"
66: #include "proc.h"
67: #include "resourcevar.h"
68: #include "buf.h"
69: #include "user.h"
70:
71: #include "vm.h"
72: #include "vm_page.h"
73: #include "vm_kern.h"
74:
75: int avefree = 0; /* XXX */
76: unsigned maxdmap = MAXDSIZ; /* XXX */
77: int readbuffers = 0; /* XXX allow kgdb to read kernel buffer pool */
78:
79: kernacc(addr, len, rw)
80: caddr_t addr;
81: int len, rw;
82: {
83: boolean_t rv;
84: vm_offset_t saddr, eaddr;
85: vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
86:
87: saddr = trunc_page(addr);
1.1.1.4 ! root 88: eaddr = round_page(addr+len);
1.1 root 89: rv = vm_map_check_protection(kernel_map, saddr, eaddr, prot);
90: /*
91: * XXX there are still some things (e.g. the buffer cache) that
92: * are managed behind the VM system's back so even though an
93: * address is accessible in the mind of the VM system, there may
94: * not be physical pages where the VM thinks there is. This can
95: * lead to bogus allocation of pages in the kernel address space
96: * or worse, inconsistencies at the pmap level. We only worry
97: * about the buffer cache for now.
98: */
99: if (!readbuffers && rv && (eaddr > (vm_offset_t)buffers &&
100: saddr < (vm_offset_t)buffers + MAXBSIZE * nbuf))
101: rv = FALSE;
102: return(rv == TRUE);
103: }
104:
105: useracc(addr, len, rw)
106: caddr_t addr;
107: int len, rw;
108: {
109: boolean_t rv;
110: vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
111:
1.1.1.4 ! root 112: /*
! 113: * XXX - specially disallow access to user page tables - they are
! 114: * in the map.
! 115: *
! 116: * XXX - don't specially disallow access to the user area - treat
! 117: * it as incorrectly as elsewhere.
! 118: *
! 119: * XXX - VM_MAXUSER_ADDRESS is an end address, not a max. It was
! 120: * only used (as an end address) in trap.c. Use it as an end
! 121: * address here too.
! 122: */
! 123: if ((vm_offset_t) addr >= VM_MAXUSER_ADDRESS
! 124: || (vm_offset_t) addr + len > VM_MAXUSER_ADDRESS
! 125: || (vm_offset_t) addr + len <= (vm_offset_t) addr)
! 126: return (FALSE);
! 127:
1.1 root 128: rv = vm_map_check_protection(&curproc->p_vmspace->vm_map,
1.1.1.4 ! root 129: trunc_page(addr), round_page(addr+len), prot);
1.1 root 130: return(rv == TRUE);
131: }
132:
133: #ifdef KGDB
134: /*
135: * Change protections on kernel pages from addr to addr+len
136: * (presumably so debugger can plant a breakpoint).
137: * All addresses are assumed to reside in the Sysmap,
138: */
139: chgkprot(addr, len, rw)
140: register caddr_t addr;
141: int len, rw;
142: {
143: vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
144:
145: vm_map_protect(kernel_map, trunc_page(addr),
1.1.1.4 ! root 146: round_page(addr+len), prot, FALSE);
1.1 root 147: }
148: #endif
149:
150: vslock(addr, len)
151: caddr_t addr;
152: u_int len;
153: {
154: vm_map_pageable(&curproc->p_vmspace->vm_map, trunc_page(addr),
1.1.1.4 ! root 155: round_page(addr+len), FALSE);
1.1 root 156: }
157:
158: vsunlock(addr, len, dirtied)
159: caddr_t addr;
160: u_int len;
161: int dirtied;
162: {
163: #ifdef lint
164: dirtied++;
165: #endif lint
166: vm_map_pageable(&curproc->p_vmspace->vm_map, trunc_page(addr),
1.1.1.4 ! root 167: round_page(addr+len), TRUE);
1.1 root 168: }
169:
170: /*
171: * Implement fork's actions on an address space.
172: * Here we arrange for the address space to be copied or referenced,
173: * allocate a user struct (pcb and kernel stack), then call the
174: * machine-dependent layer to fill those in and make the new process
175: * ready to run.
176: * NOTE: the kernel stack may be at a different location in the child
177: * process, and thus addresses of automatic variables may be invalid
178: * after cpu_fork returns in the child process. We do nothing here
179: * after cpu_fork returns.
180: */
181: vm_fork(p1, p2, isvfork)
182: register struct proc *p1, *p2;
183: int isvfork;
184: {
185: register struct user *up;
186: vm_offset_t addr;
187:
188: #ifdef i386
189: /*
190: * avoid copying any of the parent's pagetables or other per-process
191: * objects that reside in the map by marking all of them non-inheritable
192: */
193: (void)vm_map_inherit(&p1->p_vmspace->vm_map,
194: UPT_MIN_ADDRESS-UPAGES*NBPG, VM_MAX_ADDRESS, VM_INHERIT_NONE);
195: #endif
196: p2->p_vmspace = vmspace_fork(p1->p_vmspace);
197:
198: #ifdef SYSVSHM
199: if (p1->p_vmspace->vm_shm)
200: shmfork(p1, p2, isvfork);
201: #endif
202:
203: /*
204: * Allocate a wired-down (for now) pcb and kernel stack for the process
205: */
1.1.1.2 root 206: #ifdef notyet
1.1 root 207: addr = kmem_alloc_pageable(kernel_map, ctob(UPAGES));
208: vm_map_pageable(kernel_map, addr, addr + ctob(UPAGES), FALSE);
1.1.1.2 root 209: #else
210: addr = kmem_alloc(kernel_map, ctob(UPAGES));
211: #endif
1.1 root 212: up = (struct user *)addr;
213: p2->p_addr = up;
214:
215: /*
216: * p_stats and p_sigacts currently point at fields
217: * in the user struct but not at &u, instead at p_addr.
218: * Copy p_sigacts and parts of p_stats; zero the rest
219: * of p_stats (statistics).
220: */
221: p2->p_stats = &up->u_stats;
222: p2->p_sigacts = &up->u_sigacts;
223: up->u_sigacts = *p1->p_sigacts;
224: bzero(&up->u_stats.pstat_startzero,
225: (unsigned) ((caddr_t)&up->u_stats.pstat_endzero -
226: (caddr_t)&up->u_stats.pstat_startzero));
227: bcopy(&p1->p_stats->pstat_startcopy, &up->u_stats.pstat_startcopy,
228: ((caddr_t)&up->u_stats.pstat_endcopy -
229: (caddr_t)&up->u_stats.pstat_startcopy));
230:
231: #ifdef i386
232: { u_int addr = UPT_MIN_ADDRESS - UPAGES*NBPG; struct vm_map *vp;
233:
234: vp = &p2->p_vmspace->vm_map;
1.1.1.2 root 235:
236: /* ream out old pagetables and kernel stack */
237: (void)vm_deallocate(vp, addr, UPT_MAX_ADDRESS - addr);
1.1 root 238: (void)vm_allocate(vp, &addr, UPT_MAX_ADDRESS - addr, FALSE);
1.1.1.4 ! root 239:
! 240: /* protect from the user area from user accesses. :-)
! 241: addr -> addr + UPAGES*NBPG don't seem to be protected without
! 242: this; the rest seems to be OK, and doesn't like being protected
! 243: - [email protected] */
! 244: vm_protect(vp, addr, UPAGES*NBPG, FALSE, VM_PROT_NONE);
1.1 root 245: }
246: #endif
247: /*
248: * cpu_fork will copy and update the kernel stack and pcb,
249: * and make the child ready to run. It marks the child
250: * so that it can return differently than the parent.
251: * It returns twice, once in the parent process and
252: * once in the child.
253: */
254: return (cpu_fork(p1, p2));
255: }
256:
257: /*
258: * Set default limits for VM system.
259: * Called for proc 0, and then inherited by all others.
260: */
1.1.1.4 ! root 261: void
1.1 root 262: vm_init_limits(p)
263: register struct proc *p;
264: {
265:
266: /*
267: * Set up the initial limits on process VM.
268: * Set the maximum resident set size to be all
269: * of (reasonably) available memory. This causes
270: * any single, large process to start random page
271: * replacement once it fills memory.
272: */
273: p->p_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
274: p->p_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
275: p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
276: p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
277: p->p_rlimit[RLIMIT_RSS].rlim_cur = p->p_rlimit[RLIMIT_RSS].rlim_max =
278: ptoa(vm_page_free_count);
279: }
280:
281: #include "../vm/vm_pageout.h"
282:
283: #ifdef DEBUG
284: int enableswap = 1;
285: int swapdebug = 0;
286: #define SDB_FOLLOW 1
287: #define SDB_SWAPIN 2
288: #define SDB_SWAPOUT 4
289: #endif
290:
291: /*
292: * Brutally simple:
293: * 1. Attempt to swapin every swaped-out, runnable process in
294: * order of priority.
295: * 2. If not enough memory, wake the pageout daemon and let it
296: * clear some space.
297: */
1.1.1.4 ! root 298: void
1.1 root 299: sched()
300: {
301: register struct proc *p;
302: register int pri;
303: struct proc *pp;
304: int ppri;
305: vm_offset_t addr;
306: vm_size_t size;
307:
308: loop:
309: #ifdef DEBUG
310: if (!enableswap) {
311: pp = NULL;
312: goto noswap;
313: }
314: #endif
315: pp = NULL;
316: ppri = INT_MIN;
317: for (p = allproc; p != NULL; p = p->p_nxt)
318: if (p->p_stat == SRUN && (p->p_flag & SLOAD) == 0) {
319: pri = p->p_time + p->p_slptime - p->p_nice * 8;
320: if (pri > ppri) {
321: pp = p;
322: ppri = pri;
323: }
324: }
325: #ifdef DEBUG
326: if (swapdebug & SDB_FOLLOW)
327: printf("sched: running, procp %x pri %d\n", pp, ppri);
328: noswap:
329: #endif
330: /*
331: * Nothing to do, back to sleep
332: */
333: if ((p = pp) == NULL) {
1.1.1.4 ! root 334: tsleep((caddr_t)&proc0, PVM, "sched", 0);
1.1 root 335: goto loop;
336: }
337:
338: /*
339: * We would like to bring someone in.
340: * This part is really bogus cuz we could deadlock on memory
341: * despite our feeble check.
342: */
343: size = round_page(ctob(UPAGES));
344: addr = (vm_offset_t) p->p_addr;
345: if (vm_page_free_count > atop(size)) {
346: #ifdef DEBUG
347: if (swapdebug & SDB_SWAPIN)
348: printf("swapin: pid %d(%s)@%x, pri %d free %d\n",
349: p->p_pid, p->p_comm, p->p_addr,
350: ppri, vm_page_free_count);
351: #endif
352: vm_map_pageable(kernel_map, addr, addr+size, FALSE);
353: (void) splclock();
354: if (p->p_stat == SRUN)
355: setrq(p);
356: p->p_flag |= SLOAD;
357: (void) spl0();
358: p->p_time = 0;
359: goto loop;
360: }
361: /*
362: * Not enough memory, jab the pageout daemon and wait til the
363: * coast is clear.
364: */
365: #ifdef DEBUG
366: if (swapdebug & SDB_FOLLOW)
367: printf("sched: no room for pid %d(%s), free %d\n",
368: p->p_pid, p->p_comm, vm_page_free_count);
369: #endif
370: (void) splhigh();
371: VM_WAIT;
372: (void) spl0();
373: #ifdef DEBUG
374: if (swapdebug & SDB_FOLLOW)
375: printf("sched: room again, free %d\n", vm_page_free_count);
376: #endif
377: goto loop;
378: }
379:
380: #define swappable(p) \
381: (((p)->p_flag & (SSYS|SLOAD|SKEEP|SWEXIT|SPHYSIO)) == SLOAD)
382:
383: /*
384: * Swapout is driven by the pageout daemon. Very simple, we find eligible
385: * procs and unwire their u-areas. We try to always "swap" at least one
386: * process in case we need the room for a swapin.
387: * If any procs have been sleeping/stopped for at least maxslp seconds,
388: * they are swapped. Else, we swap the longest-sleeping or stopped process,
389: * if any, otherwise the longest-resident process.
390: */
391: swapout_threads()
392: {
393: register struct proc *p;
394: struct proc *outp, *outp2;
395: int outpri, outpri2;
396: int didswap = 0;
397: extern int maxslp;
398:
399: #ifdef DEBUG
400: if (!enableswap)
401: return;
402: #endif
403: outp = outp2 = NULL;
404: outpri = outpri2 = 0;
405: for (p = allproc; p != NULL; p = p->p_nxt) {
406: if (!swappable(p))
407: continue;
408: switch (p->p_stat) {
409: case SRUN:
410: if (p->p_time > outpri2) {
411: outp2 = p;
412: outpri2 = p->p_time;
413: }
414: continue;
415:
416: case SSLEEP:
417: case SSTOP:
418: if (p->p_slptime > maxslp) {
419: swapout(p);
420: didswap++;
421: } else if (p->p_slptime > outpri) {
422: outp = p;
423: outpri = p->p_slptime;
424: }
425: continue;
426: }
427: }
428: /*
429: * If we didn't get rid of any real duds, toss out the next most
430: * likely sleeping/stopped or running candidate. We only do this
431: * if we are real low on memory since we don't gain much by doing
432: * it (UPAGES pages).
433: */
434: if (didswap == 0 &&
435: vm_page_free_count <= atop(round_page(ctob(UPAGES)))) {
436: if ((p = outp) == 0)
437: p = outp2;
438: #ifdef DEBUG
439: if (swapdebug & SDB_SWAPOUT)
440: printf("swapout_threads: no duds, try procp %x\n", p);
441: #endif
442: if (p)
443: swapout(p);
444: }
445: }
446:
447: swapout(p)
448: register struct proc *p;
449: {
450: vm_offset_t addr;
451: vm_size_t size;
452:
453: #ifdef DEBUG
454: if (swapdebug & SDB_SWAPOUT)
455: printf("swapout: pid %d(%s)@%x, stat %x pri %d free %d\n",
456: p->p_pid, p->p_comm, p->p_addr, p->p_stat,
457: p->p_slptime, vm_page_free_count);
458: #endif
459: size = round_page(ctob(UPAGES));
460: addr = (vm_offset_t) p->p_addr;
1.1.1.2 root 461: #ifdef notyet
1.1 root 462: #ifdef hp300
463: /*
464: * Ugh! u-area is double mapped to a fixed address behind the
465: * back of the VM system and accesses are usually through that
466: * address rather than the per-process address. Hence reference
467: * and modify information are recorded at the fixed address and
468: * lost at context switch time. We assume the u-struct and
469: * kernel stack are always accessed/modified and force it to be so.
470: */
471: {
472: register int i;
473: volatile long tmp;
474:
475: for (i = 0; i < UPAGES; i++) {
476: tmp = *(long *)addr; *(long *)addr = tmp;
477: addr += NBPG;
478: }
479: addr = (vm_offset_t) p->p_addr;
480: }
481: #endif
482: vm_map_pageable(kernel_map, addr, addr+size, TRUE);
483: pmap_collect(vm_map_pmap(&p->p_vmspace->vm_map));
1.1.1.2 root 484: #endif
1.1 root 485: (void) splhigh();
486: p->p_flag &= ~SLOAD;
487: if (p->p_stat == SRUN)
488: remrq(p);
489: (void) spl0();
490: p->p_time = 0;
491: }
492:
493: /*
494: * The rest of these routines fake thread handling
495: */
496:
497: void
498: assert_wait(event, ruptible)
499: int event;
500: boolean_t ruptible;
501: {
502: #ifdef lint
503: ruptible++;
504: #endif
505: curproc->p_thread = event;
506: }
507:
508: void
509: thread_block()
510: {
511: int s = splhigh();
512:
513: if (curproc->p_thread)
1.1.1.4 ! root 514: tsleep((caddr_t)curproc->p_thread, PVM, "thrd_block", 0);
1.1 root 515: splx(s);
516: }
517:
518: thread_sleep(event, lock, ruptible)
519: int event;
520: simple_lock_t lock;
521: boolean_t ruptible;
522: {
523: #ifdef lint
524: ruptible++;
525: #endif
526: int s = splhigh();
527:
528: curproc->p_thread = event;
529: simple_unlock(lock);
530: if (curproc->p_thread)
1.1.1.4 ! root 531: tsleep((caddr_t)event, PVM, "thrd_sleep", 0);
1.1 root 532: splx(s);
533: }
534:
535: thread_wakeup(event)
536: int event;
537: {
538: int s = splhigh();
539:
540: wakeup((caddr_t)event);
541: splx(s);
542: }
543:
544: /*
545: * DEBUG stuff
546: */
547:
548: int indent = 0;
549:
550: /*ARGSUSED2*/
551: iprintf(a, b, c, d, e, f, g, h)
552: char *a;
553: {
554: register int i;
555:
556: i = indent;
557: while (i >= 8) {
558: printf("\t");
559: i -= 8;
560: }
561: for (; i > 0; --i)
562: printf(" ");
563: printf(a, b, c, d, e, f, g, h);
564: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.