Annotation of sys/uvm/uvm_glue.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: uvm_glue.c,v 1.47 2007/05/26 20:26:51 pedro Exp $ */
! 2: /* $NetBSD: uvm_glue.c,v 1.44 2001/02/06 19:54:44 eeh Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1997 Charles D. Cranor and Washington University.
! 6: * Copyright (c) 1991, 1993, The Regents of the University of California.
! 7: *
! 8: * All rights reserved.
! 9: *
! 10: * This code is derived from software contributed to Berkeley by
! 11: * The Mach Operating System project at Carnegie-Mellon University.
! 12: *
! 13: * Redistribution and use in source and binary forms, with or without
! 14: * modification, are permitted provided that the following conditions
! 15: * are met:
! 16: * 1. Redistributions of source code must retain the above copyright
! 17: * notice, this list of conditions and the following disclaimer.
! 18: * 2. Redistributions in binary form must reproduce the above copyright
! 19: * notice, this list of conditions and the following disclaimer in the
! 20: * documentation and/or other materials provided with the distribution.
! 21: * 3. All advertising materials mentioning features or use of this software
! 22: * must display the following acknowledgement:
! 23: * This product includes software developed by Charles D. Cranor,
! 24: * Washington University, the University of California, Berkeley and
! 25: * its contributors.
! 26: * 4. Neither the name of the University nor the names of its contributors
! 27: * may be used to endorse or promote products derived from this software
! 28: * without specific prior written permission.
! 29: *
! 30: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 31: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 32: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 33: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 34: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 35: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 36: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 37: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 38: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 39: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 40: * SUCH DAMAGE.
! 41: *
! 42: * @(#)vm_glue.c 8.6 (Berkeley) 1/5/94
! 43: * from: Id: uvm_glue.c,v 1.1.2.8 1998/02/07 01:16:54 chs Exp
! 44: *
! 45: *
! 46: * Copyright (c) 1987, 1990 Carnegie-Mellon University.
! 47: * All rights reserved.
! 48: *
! 49: * Permission to use, copy, modify and distribute this software and
! 50: * its documentation is hereby granted, provided that both the copyright
! 51: * notice and this permission notice appear in all copies of the
! 52: * software, derivative works or modified versions, and any portions
! 53: * thereof, and that both notices appear in supporting documentation.
! 54: *
! 55: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
! 56: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
! 57: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
! 58: *
! 59: * Carnegie Mellon requests users of this software to return to
! 60: *
! 61: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
! 62: * School of Computer Science
! 63: * Carnegie Mellon University
! 64: * Pittsburgh PA 15213-3890
! 65: *
! 66: * any improvements or extensions that they make and grant Carnegie the
! 67: * rights to redistribute these changes.
! 68: */
! 69:
! 70: /*
! 71: * uvm_glue.c: glue functions
! 72: */
! 73:
! 74: #include <sys/param.h>
! 75: #include <sys/systm.h>
! 76: #include <sys/proc.h>
! 77: #include <sys/resourcevar.h>
! 78: #include <sys/buf.h>
! 79: #include <sys/user.h>
! 80: #ifdef SYSVSHM
! 81: #include <sys/shm.h>
! 82: #endif
! 83: #include <sys/sched.h>
! 84:
! 85: #include <uvm/uvm.h>
! 86:
! 87: #include <machine/cpu.h>
! 88:
! 89: /*
! 90: * XXXCDC: do these really belong here?
! 91: */
! 92:
! 93: int readbuffers = 0; /* allow KGDB to read kern buffer pool */
! 94: /* XXX: see uvm_kernacc */
! 95:
! 96:
! 97: /*
! 98: * uvm_kernacc: can the kernel access a region of memory
! 99: *
! 100: * - called from malloc [DIAGNOSTIC], and /dev/kmem driver (mem.c)
! 101: */
! 102:
! 103: boolean_t
! 104: uvm_kernacc(addr, len, rw)
! 105: caddr_t addr;
! 106: size_t len;
! 107: int rw;
! 108: {
! 109: boolean_t rv;
! 110: vaddr_t saddr, eaddr;
! 111: vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
! 112:
! 113: saddr = trunc_page((vaddr_t)addr);
! 114: eaddr = round_page((vaddr_t)addr + len);
! 115: vm_map_lock_read(kernel_map);
! 116: rv = uvm_map_checkprot(kernel_map, saddr, eaddr, prot);
! 117: vm_map_unlock_read(kernel_map);
! 118:
! 119: return(rv);
! 120: }
! 121:
! 122: #ifdef KGDB
! 123: /*
! 124: * Change protections on kernel pages from addr to addr+len
! 125: * (presumably so debugger can plant a breakpoint).
! 126: *
! 127: * We force the protection change at the pmap level. If we were
! 128: * to use vm_map_protect a change to allow writing would be lazily-
! 129: * applied meaning we would still take a protection fault, something
! 130: * we really don't want to do. It would also fragment the kernel
! 131: * map unnecessarily. We cannot use pmap_protect since it also won't
! 132: * enforce a write-enable request. Using pmap_enter is the only way
! 133: * we can ensure the change takes place properly.
! 134: */
! 135: void
! 136: uvm_chgkprot(addr, len, rw)
! 137: caddr_t addr;
! 138: size_t len;
! 139: int rw;
! 140: {
! 141: vm_prot_t prot;
! 142: paddr_t pa;
! 143: vaddr_t sva, eva;
! 144:
! 145: prot = rw == B_READ ? VM_PROT_READ : VM_PROT_READ|VM_PROT_WRITE;
! 146: eva = round_page((vaddr_t)addr + len);
! 147: for (sva = trunc_page((vaddr_t)addr); sva < eva; sva += PAGE_SIZE) {
! 148: /*
! 149: * Extract physical address for the page.
! 150: * We use a cheezy hack to differentiate physical
! 151: * page 0 from an invalid mapping, not that it
! 152: * really matters...
! 153: */
! 154: if (pmap_extract(pmap_kernel(), sva, &pa) == FALSE)
! 155: panic("chgkprot: invalid page");
! 156: pmap_enter(pmap_kernel(), sva, pa, prot, PMAP_WIRED);
! 157: }
! 158: pmap_update(pmap_kernel());
! 159: }
! 160: #endif
! 161:
! 162: /*
! 163: * uvm_vslock: wire user memory for I/O
! 164: *
! 165: * - called from physio and sys___sysctl
! 166: * - XXXCDC: consider nuking this (or making it a macro?)
! 167: */
! 168:
! 169: int
! 170: uvm_vslock(p, addr, len, access_type)
! 171: struct proc *p;
! 172: caddr_t addr;
! 173: size_t len;
! 174: vm_prot_t access_type;
! 175: {
! 176: vm_map_t map;
! 177: vaddr_t start, end;
! 178: int rv;
! 179:
! 180: map = &p->p_vmspace->vm_map;
! 181: start = trunc_page((vaddr_t)addr);
! 182: end = round_page((vaddr_t)addr + len);
! 183: if (end <= start)
! 184: return (EINVAL);
! 185:
! 186: rv = uvm_fault_wire(map, start, end, access_type);
! 187:
! 188: return (rv);
! 189: }
! 190:
! 191: /*
! 192: * uvm_vsunlock: unwire user memory wired by uvm_vslock()
! 193: *
! 194: * - called from physio and sys___sysctl
! 195: * - XXXCDC: consider nuking this (or making it a macro?)
! 196: */
! 197:
! 198: void
! 199: uvm_vsunlock(p, addr, len)
! 200: struct proc *p;
! 201: caddr_t addr;
! 202: size_t len;
! 203: {
! 204: vaddr_t start, end;
! 205:
! 206: start = trunc_page((vaddr_t)addr);
! 207: end = round_page((vaddr_t)addr + len);
! 208: if (end <= start)
! 209: return;
! 210:
! 211: uvm_fault_unwire(&p->p_vmspace->vm_map, start, end);
! 212: }
! 213:
! 214: /*
! 215: * uvm_fork: fork a virtual address space
! 216: *
! 217: * - the address space is copied as per parent map's inherit values
! 218: * - a new "user" structure is allocated for the child process
! 219: * [filled in by MD layer...]
! 220: * - if specified, the child gets a new user stack described by
! 221: * stack and stacksize
! 222: * - NOTE: the kernel stack may be at a different location in the child
! 223: * process, and thus addresses of automatic variables may be invalid
! 224: * after cpu_fork returns in the child process. We do nothing here
! 225: * after cpu_fork returns.
! 226: * - XXXCDC: we need a way for this to return a failure value rather
! 227: * than just hang
! 228: */
! 229: void
! 230: uvm_fork(p1, p2, shared, stack, stacksize, func, arg)
! 231: struct proc *p1, *p2;
! 232: boolean_t shared;
! 233: void *stack;
! 234: size_t stacksize;
! 235: void (*func)(void *);
! 236: void *arg;
! 237: {
! 238: struct user *up = p2->p_addr;
! 239:
! 240: if (shared == TRUE) {
! 241: p2->p_vmspace = NULL;
! 242: uvmspace_share(p1, p2); /* share vmspace */
! 243: } else
! 244: p2->p_vmspace = uvmspace_fork(p1->p_vmspace); /* fork vmspace */
! 245:
! 246: #ifdef PMAP_UAREA
! 247: /* Tell the pmap this is a u-area mapping */
! 248: PMAP_UAREA((vaddr_t)up);
! 249: #endif
! 250:
! 251: /*
! 252: * p_stats currently points at a field in the user struct. Copy
! 253: * parts of p_stats, and zero out the rest.
! 254: */
! 255: p2->p_stats = &up->u_stats;
! 256: memset(&up->u_stats.pstat_startzero, 0,
! 257: ((caddr_t)&up->u_stats.pstat_endzero -
! 258: (caddr_t)&up->u_stats.pstat_startzero));
! 259: memcpy(&up->u_stats.pstat_startcopy, &p1->p_stats->pstat_startcopy,
! 260: ((caddr_t)&up->u_stats.pstat_endcopy -
! 261: (caddr_t)&up->u_stats.pstat_startcopy));
! 262:
! 263: /*
! 264: * cpu_fork() copy and update the pcb, and make the child ready
! 265: * to run. If this is a normal user fork, the child will exit
! 266: * directly to user mode via child_return() on its first time
! 267: * slice and will not return here. If this is a kernel thread,
! 268: * the specified entry point will be executed.
! 269: */
! 270: cpu_fork(p1, p2, stack, stacksize, func, arg);
! 271: }
! 272:
! 273: /*
! 274: * uvm_exit: exit a virtual address space
! 275: *
! 276: * - the process passed to us is a dead (pre-zombie) process; we
! 277: * are running on a different context now (the reaper).
! 278: * - we must run in a separate thread because freeing the vmspace
! 279: * of the dead process may block.
! 280: */
! 281: void
! 282: uvm_exit(struct proc *p)
! 283: {
! 284: uvmspace_free(p->p_vmspace);
! 285: uvm_km_free(kernel_map, (vaddr_t)p->p_addr, USPACE);
! 286: p->p_addr = NULL;
! 287: }
! 288:
! 289: /*
! 290: * uvm_init_limit: init per-process VM limits
! 291: *
! 292: * - called for process 0 and then inherited by all others.
! 293: */
! 294: void
! 295: uvm_init_limits(struct proc *p)
! 296: {
! 297:
! 298: /*
! 299: * Set up the initial limits on process VM. Set the maximum
! 300: * resident set size to be all of (reasonably) available memory.
! 301: * This causes any single, large process to start random page
! 302: * replacement once it fills memory.
! 303: */
! 304:
! 305: p->p_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
! 306: p->p_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
! 307: p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
! 308: p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
! 309: p->p_rlimit[RLIMIT_RSS].rlim_cur = ptoa(uvmexp.free);
! 310: }
! 311:
! 312: #ifdef DEBUG
! 313: int enableswap = 1;
! 314: int swapdebug = 0;
! 315: #define SDB_FOLLOW 1
! 316: #define SDB_SWAPIN 2
! 317: #define SDB_SWAPOUT 4
! 318: #endif
! 319:
! 320: /*
! 321: * uvm_scheduler: process zero main loop
! 322: *
! 323: * - if not enough memory, wake the pagedaemon and let it clear space.
! 324: */
! 325:
! 326: void
! 327: uvm_scheduler(void)
! 328: {
! 329: /*
! 330: * Nothing to do, back to sleep
! 331: */
! 332: while (1)
! 333: tsleep(&proc0, PVM, "scheduler", 0);
! 334: }
! 335:
! 336: /*
! 337: * swappable: is process "p" swappable?
! 338: */
! 339:
! 340: #define swappable(p) (((p)->p_flag & (P_SYSTEM | P_WEXIT)) == 0)
! 341:
! 342: /*
! 343: * swapout_threads: find threads that can be swapped
! 344: *
! 345: * - called by the pagedaemon
! 346: * - try and swap at least one processs
! 347: * - processes that are sleeping or stopped for maxslp or more seconds
! 348: * are swapped... otherwise the longest-sleeping or stopped process
! 349: * is swapped, otherwise the longest resident process...
! 350: */
! 351: void
! 352: uvm_swapout_threads(void)
! 353: {
! 354: struct proc *p;
! 355: struct proc *outp, *outp2;
! 356: int outpri, outpri2;
! 357: int didswap = 0;
! 358: extern int maxslp;
! 359: /* XXXCDC: should move off to uvmexp. or uvm., also in uvm_meter */
! 360:
! 361: #ifdef DEBUG
! 362: if (!enableswap)
! 363: return;
! 364: #endif
! 365:
! 366: /*
! 367: * outp/outpri : stop/sleep process with largest sleeptime < maxslp
! 368: * outp2/outpri2: the longest resident process (its swap time)
! 369: */
! 370: outp = outp2 = NULL;
! 371: outpri = outpri2 = 0;
! 372: LIST_FOREACH(p, &allproc, p_list) {
! 373: if (!swappable(p))
! 374: continue;
! 375: switch (p->p_stat) {
! 376: case SRUN:
! 377: if (p->p_swtime > outpri2) {
! 378: outp2 = p;
! 379: outpri2 = p->p_swtime;
! 380: }
! 381: continue;
! 382:
! 383: case SSLEEP:
! 384: case SSTOP:
! 385: if (p->p_slptime >= maxslp) {
! 386: pmap_collect(p->p_vmspace->vm_map.pmap);
! 387: didswap++;
! 388: } else if (p->p_slptime > outpri) {
! 389: outp = p;
! 390: outpri = p->p_slptime;
! 391: }
! 392: continue;
! 393: }
! 394: }
! 395:
! 396: /*
! 397: * If we didn't get rid of any real duds, toss out the next most
! 398: * likely sleeping/stopped or running candidate. We only do this
! 399: * if we are real low on memory since we don't gain much by doing
! 400: * it.
! 401: */
! 402: if (didswap == 0 && uvmexp.free <= atop(round_page(USPACE))) {
! 403: if ((p = outp) == NULL)
! 404: p = outp2;
! 405: #ifdef DEBUG
! 406: if (swapdebug & SDB_SWAPOUT)
! 407: printf("swapout_threads: no duds, try procp %p\n", p);
! 408: #endif
! 409: if (p)
! 410: pmap_collect(p->p_vmspace->vm_map.pmap);
! 411: }
! 412: }
CVSweb