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