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