xref: /original-bsd/sys/vm/vm_glue.c (revision dd262573)
1 /*
2  * Copyright (c) 1987 Carnegie-Mellon University
3  * Copyright (c) 1991 Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * The Mach Operating System project at Carnegie-Mellon University.
8  *
9  * The CMU software License Agreement specifies the terms and conditions
10  * for use and redistribution.
11  *
12  *	@(#)vm_glue.c	7.1 (Berkeley) 12/05/90
13  */
14 
15 #include "param.h"
16 #include "systm.h"
17 #include "user.h"
18 #include "proc.h"
19 #include "buf.h"
20 
21 #include "../vm/vm_param.h"
22 #include "../vm/vm_map.h"
23 #include "../vm/vm_page.h"
24 #include "../vm/vm_kern.h"
25 
26 int	avefree = 0;		/* XXX */
27 unsigned maxdmap = MAXDSIZ;	/* XXX */
28 
29 kernacc(addr, len, rw)
30 	caddr_t addr;
31 	int len, rw;
32 {
33 	boolean_t rv;
34 	vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
35 
36 	rv = vm_map_check_protection(kernel_map, trunc_page(addr),
37 				     round_page(addr+len-1), prot);
38 	return(rv == TRUE);
39 }
40 
41 useracc(addr, len, rw)
42 	caddr_t addr;
43 	int len, rw;
44 {
45 	boolean_t rv;
46 	vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
47 
48 	rv = vm_map_check_protection(u.u_procp->p_map, trunc_page(addr),
49 				     round_page(addr+len-1), prot);
50 	return(rv == TRUE);
51 }
52 
53 #ifdef KGDB
54 /*
55  * Change protections on kernel pages from addr to addr+size
56  * (presumably so debugger can plant a breakpoint).
57  * All addresses are assumed to reside in the Sysmap,
58  */
59 chgkprot(addr, len, rw)
60 	register caddr_t addr;
61 	int len, rw;
62 {
63 	vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
64 
65 	vm_map_protect(kernel_map, trunc_page(addr),
66 		       round_page(addr+len-1), prot, FALSE);
67 }
68 #endif
69 
70 vslock(addr, len)
71 	caddr_t	addr;
72 	u_int	len;
73 {
74 	vm_map_pageable(u.u_procp->p_map, trunc_page(addr),
75 			round_page(addr+len-1), FALSE);
76 }
77 
78 vsunlock(addr, len, dirtied)
79 	caddr_t	addr;
80 	u_int	len;
81 	int dirtied;
82 {
83 #ifdef	lint
84 	dirtied++;
85 #endif	lint
86 	vm_map_pageable(u.u_procp->p_map, trunc_page(addr),
87 			round_page(addr+len-1), TRUE);
88 }
89 
90 procdup(p, isvfork)
91 	register struct proc *p;
92 	int isvfork;
93 {
94 	register struct user *up;
95 	vm_offset_t addr;
96 	vm_size_t size;
97 
98 #if 0
99 	/*
100 	 * Duplicate the process address space.
101 	 * XXX if this is a vfork we arrange to share data/stack to
102 	 *     preserve brain-dead semantics of vfork().
103 	 * XXX this doesn't work due to a bug in the VM code.
104 	 *     Once a process has done a vfork setting up sharing maps,
105 	 *     any future forks may fail as the source VM range doesn't
106 	 *     properly get write-protected.  This causes the parent to
107 	 *     not create copies and instead modifies the originals.
108 	 *     If the parent activates before the child, the child will
109 	 *     get a corrupted address space.
110 	 */
111 	if (isvfork) {
112 		addr = trunc_page(u.u_daddr);
113 		size = ctob(u.u_dsize);
114 		(void) vm_map_inherit(u.u_procp->p_map, addr,
115 				      addr + size, VM_INHERIT_SHARE);
116 		(void) vm_map_inherit(u.u_procp->p_map, u.u_maxsaddr,
117 				      VM_MAX_ADDRESS, VM_INHERIT_SHARE);
118 	}
119 #endif
120 	p->p_map = vm_map_fork(u.u_procp->p_map);
121 #if 0
122 	if (isvfork) {
123 		(void) vm_map_inherit(u.u_procp->p_map, addr,
124 				      addr + size, VM_INHERIT_COPY);
125 		(void) vm_map_inherit(u.u_procp->p_map, u.u_maxsaddr,
126 				      VM_MAX_ADDRESS, VM_INHERIT_COPY);
127 	}
128 #endif
129 	/*
130 	 * Allocate a wired-down (for now) u-area for the process
131 	 */
132 	size = round_page(ctob(UPAGES));
133 	addr = kmem_alloc_pageable(kernel_map, size);
134 	vm_map_pageable(kernel_map, addr, addr+size, FALSE);
135 	p->p_addr = (caddr_t)addr;
136 	up = (struct user *)addr;
137 
138 	/*
139 	 * Update the current u-area and copy it to the new one
140 	 */
141 	resume(pcbb(u.u_procp));
142 	bcopy(u.u_procp->p_addr, p->p_addr, size);
143 	up->u_procp = p;
144 	PMAP_ACTIVATE(p->p_map->pmap, (struct pcb *)p->p_addr);
145 
146 	/*
147 	 * Arrange for a non-local goto when the new process
148 	 * is started, to resume here, returning nonzero from setjmp.
149 	 */
150 	up->u_pcb.pcb_sswap = (int *)&u.u_ssave;
151 	if (savectx(&up->u_ssave)) {
152 		/*
153 		 * Return 1 in child.
154 		 */
155 		return (1);
156 	}
157 
158 	/*
159 	 * Clear vm statistics of new process.
160 	 */
161 	bzero((caddr_t)&up->u_ru, sizeof (struct rusage));
162 	bzero((caddr_t)&up->u_cru, sizeof (struct rusage));
163 	up->u_outime = 0;
164 	return (0);
165 }
166 
167 /*
168  * XXX Scaled down version from vm_page.c
169  */
170 vminit()
171 {
172 	/*
173 	 * Set up the initial limits on process VM.
174 	 * Set the maximum resident set size to be all
175 	 * of (reasonably) available memory.  This causes
176 	 * any single, large process to start random page
177 	 * replacement once it fills memory.
178 	 */
179         u.u_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
180         u.u_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
181         u.u_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
182         u.u_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
183 	u.u_rlimit[RLIMIT_RSS].rlim_cur = u.u_rlimit[RLIMIT_RSS].rlim_max =
184 		ptoa(vm_page_free_count);
185 	proc[0].p_maxrss = vm_page_free_count;
186 }
187 
188 #include "../vm/vm_pageout.h"
189 
190 #ifdef DEBUG
191 int	enableswap = 1;
192 int	swapdebug = 0;
193 #define	SDB_FOLLOW	1
194 #define SDB_SWAPIN	2
195 #define SDB_SWAPOUT	4
196 #endif
197 
198 /*
199  * Brutally simple:
200  *	1. Attempt to swapin every swaped-out, runnable process in
201  *	   order of priority.
202  *	2. If not enough memory, wake the pageout daemon and let it
203  *	   clear some space.
204  */
205 sched()
206 {
207 	register struct proc *rp;
208 	register int rppri;
209 	struct proc *inp;
210 	int inpri;
211 	vm_offset_t addr;
212 	vm_size_t size;
213 
214 loop:
215 #ifdef DEBUG
216 	if (!enableswap) {
217 		inp = NULL;
218 		goto noswap;
219 	}
220 #endif
221 	wantin = 0;
222 	inp = NULL;
223 	inpri = -20000;
224 	for (rp = allproc; rp != NULL; rp = rp->p_nxt)
225 		if (rp->p_stat == SRUN && (rp->p_flag & SLOAD) == 0) {
226 			rppri = rp->p_time +
227 				rp->p_slptime - (rp->p_nice-NZERO)*8;
228 			if (rppri > inpri) {
229 				inp = rp;
230 				inpri = rppri;
231 			}
232 		}
233 #ifdef DEBUG
234 	if (swapdebug & SDB_FOLLOW)
235 		printf("sched: running, procp %x pri %d\n", inp, inpri);
236 noswap:
237 #endif
238 	/*
239 	 * Nothing to do, back to sleep
240 	 */
241 	if ((rp = inp) == NULL) {
242 		(void) splhigh();
243 		runout++;
244 		sleep((caddr_t)&runout, PVM);
245 		(void) spl0();
246 		goto loop;
247 	}
248 	/*
249 	 * We would like to bring someone in.
250 	 * This part is really bogus cuz we could deadlock on memory
251 	 * despite our feeble check.
252 	 */
253 	size = round_page(ctob(UPAGES));
254 	addr = (vm_offset_t) rp->p_addr;
255 	if (vm_page_free_count > atop(size)) {
256 #ifdef DEBUG
257 		if (swapdebug & SDB_SWAPIN)
258 			printf("swapin: pid %d(%s)@%x, pri %d free %d\n",
259 			       rp->p_pid, rp->p_comm, rp->p_addr,
260 			       inpri, vm_page_free_count);
261 #endif
262 		vm_map_pageable(kernel_map, addr, addr+size, FALSE);
263 		(void) splclock();
264 		if (rp->p_stat == SRUN)
265 			setrq(rp);
266 		rp->p_flag |= SLOAD;
267 		(void) spl0();
268 		rp->p_time = 0;
269 		goto loop;
270 	}
271 	/*
272 	 * Not enough memory, jab the pageout daemon and wait til the
273 	 * coast is clear.
274 	 */
275 #ifdef DEBUG
276 	if (swapdebug & SDB_FOLLOW)
277 		printf("sched: no room for pid %d(%s), free %d\n",
278 		       rp->p_pid, rp->p_comm, vm_page_free_count);
279 #endif
280 	(void) splhigh();
281 	VM_WAIT;
282 	(void) spl0();
283 #ifdef DEBUG
284 	if (swapdebug & SDB_FOLLOW)
285 		printf("sched: room again, free %d\n", vm_page_free_count);
286 #endif
287 	goto loop;
288 }
289 
290 #define	swappable(p) \
291 	(((p)->p_flag & (SSYS|SULOCK|SLOAD|SKEEP|SWEXIT|SPHYSIO)) == SLOAD)
292 
293 /*
294  * Swapout is driven by the pageout daemon.  Very simple, we find eligible
295  * procs and unwire their u-areas.  We try to always "swap" at least one
296  * process in case we need the room for a swapin.
297  */
298 swapout_threads()
299 {
300 	register struct proc *rp;
301 	struct proc *outp, *outp2;
302 	int outpri, outpri2;
303 	int didswap = 0;
304 	extern int maxslp;
305 
306 #ifdef DEBUG
307 	if (!enableswap)
308 		return;
309 #endif
310 	outp = outp2 = NULL;
311 	outpri = outpri2 = -20000;
312 	for (rp = allproc; rp != NULL; rp = rp->p_nxt) {
313 		if (!swappable(rp))
314 			continue;
315 		switch(rp->p_stat) {
316 		case SRUN:
317 			if (rp->p_slptime > outpri2) {
318 				outp2 = rp;
319 				outpri2 = rp->p_slptime;
320 			}
321 			continue;
322 
323 		case SSLEEP:
324 		case SSTOP:
325 			if (rp->p_slptime > maxslp) {
326 				swapout(rp);
327 				didswap++;
328 			} else if (rp->p_slptime > outpri) {
329 				outp = rp;
330 				outpri = rp->p_slptime;
331 			}
332 			continue;
333 		}
334 	}
335 	/*
336 	 * If we didn't get rid of any real duds, toss out the next most
337 	 * likely sleeping/stopped or running candidate.  We only do this
338 	 * if we are real low on memory since we don't gain much by doing
339 	 * it (UPAGES pages).
340 	 */
341 	if (didswap == 0 &&
342 	    vm_page_free_count <= atop(round_page(ctob(UPAGES)))) {
343 		if ((rp = outp) == 0)
344 			rp = outp2;
345 #ifdef DEBUG
346 		if (swapdebug & SDB_SWAPOUT)
347 			printf("swapout_threads: no duds, try procp %x\n", rp);
348 #endif
349 		if (rp)
350 			swapout(rp);
351 	}
352 }
353 
354 swapout(p)
355 	register struct proc *p;
356 {
357 	vm_offset_t addr;
358 	vm_size_t size;
359 
360 #ifdef DEBUG
361 	if (swapdebug & SDB_SWAPOUT)
362 		printf("swapout: pid %d(%s)@%x, stat %x pri %d free %d\n",
363 		       p->p_pid, p->p_comm, p->p_addr, p->p_stat,
364 		       p->p_slptime, vm_page_free_count);
365 #endif
366 	size = round_page(ctob(UPAGES));
367 	addr = (vm_offset_t) p->p_addr;
368 	vm_map_pageable(kernel_map, addr, addr+size, TRUE);
369 	pmap_collect(vm_map_pmap(p->p_map));
370 	(void) splhigh();
371 	p->p_flag &= ~SLOAD;
372 	if (p->p_stat == SRUN)
373 		remrq(p);
374 	(void) spl0();
375 	p->p_time = 0;
376 }
377 
378 /*
379  * The rest of these routines fake thread handling
380  */
381 
382 void
383 assert_wait(event, ruptible)
384 	int event;
385 	boolean_t ruptible;
386 {
387 #ifdef lint
388 	ruptible++;
389 #endif
390 	u.u_procp->p_thread = event;
391 }
392 
393 void
394 thread_block()
395 {
396 	int s = splhigh();
397 
398 	if (u.u_procp->p_thread)
399 		sleep((caddr_t)u.u_procp->p_thread, PVM);
400 	splx(s);
401 }
402 
403 void
404 thread_sleep(event, lock, ruptible)
405 	int event;
406 	simple_lock_t lock;
407 	boolean_t ruptible;
408 {
409 #ifdef lint
410 	ruptible++;
411 #endif
412 	int s = splhigh();
413 
414 	u.u_procp->p_thread = event;
415 	simple_unlock(lock);
416 	if (u.u_procp->p_thread)
417 		sleep((caddr_t)u.u_procp->p_thread, PVM);
418 	splx(s);
419 }
420 
421 void
422 thread_wakeup(event)
423 	int event;
424 {
425 	int s = splhigh();
426 
427 	wakeup((caddr_t)event);
428 	splx(s);
429 }
430 
431 /*
432  * DEBUG stuff
433  */
434 
435 int indent = 0;
436 
437 /*ARGSUSED2*/
438 iprintf(a, b, c, d, e, f, g, h)
439 	char *a;
440 {
441 	register int i;
442 
443 	for (i = indent; i > 0; ) {
444 		if (i >= 8) {
445 			putchar('\t', 1, (caddr_t)0);
446 			i -= 8;
447 		} else {
448 			putchar(' ', 1, (caddr_t)0);
449 			i--;
450 		}
451 	}
452 	printf(a, b, c, d, e, f, g, h);
453 }
454