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