|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)vm_proc.c 7.11 (Berkeley) 6/30/90 ! 21: */ ! 22: ! 23: #include "param.h" ! 24: #include "systm.h" ! 25: #include "user.h" ! 26: #include "proc.h" ! 27: #include "map.h" ! 28: #include "cmap.h" ! 29: #include "text.h" ! 30: #include "vm.h" ! 31: ! 32: #include "machine/pte.h" ! 33: #include "machine/mtpr.h" ! 34: #include "machine/cpu.h" ! 35: ! 36: /* ! 37: * Get virtual memory resources for a new process. ! 38: * Called after page tables are allocated, but before they ! 39: * are initialized, we initialize the memory management registers, ! 40: * and then expand the page tables for the data and stack segments ! 41: * creating zero fill pte's there. Text pte's are set up elsewhere. ! 42: * ! 43: * SHOULD FREE EXTRA PAGE TABLE PAGES HERE OR SOMEWHERE. ! 44: */ ! 45: vgetvm(ts, ds, ss) ! 46: segsz_t ts, ds, ss; ! 47: { ! 48: ! 49: #if defined(vax) ! 50: u.u_pcb.pcb_p0lr = AST_NONE; ! 51: setp0lr(ts); ! 52: setp1lr(P1PAGES - HIGHPAGES); ! 53: #endif ! 54: #if defined(tahoe) ! 55: setp0lr(ts); ! 56: setp1lr(0); ! 57: setp2lr(P2PAGES - HIGHPAGES); ! 58: #endif ! 59: #if defined(hp300) || defined(i386) ! 60: setp0lr(LOWPAGES + ts); ! 61: setp1lr(P1PAGES - HIGHPAGES); ! 62: #endif ! 63: u.u_procp->p_tsize = ts; ! 64: u.u_tsize = ts; ! 65: expand((int)ss, 1); ! 66: expand((int)ds, 0); ! 67: } ! 68: ! 69: /* ! 70: * Release the virtual memory resources (memory ! 71: * pages, and swap area) associated with the current process. ! 72: * Caller must not be swappable. Used at exit or execl. ! 73: */ ! 74: vrelvm() ! 75: { ! 76: register struct proc *p = u.u_procp; ! 77: ! 78: /* ! 79: * Release memory; text first, then data and stack pages. ! 80: */ ! 81: xfree(); ! 82: p->p_rssize -= vmemfree(dptopte(p, 0), (int)p->p_dsize); ! 83: p->p_rssize -= vmemfree(sptopte(p, p->p_ssize - 1), (int)p->p_ssize); ! 84: if (p->p_rssize != 0) ! 85: panic("vrelvm rss"); ! 86: /* ! 87: * Wait for all page outs to complete, then ! 88: * release swap space. ! 89: */ ! 90: p->p_swrss = 0; ! 91: while (p->p_poip) ! 92: sleep((caddr_t)&p->p_poip, PSWP+1); ! 93: (void) vsexpand((segsz_t)0, &u.u_dmap, 1); ! 94: (void) vsexpand((segsz_t)0, &u.u_smap, 1); ! 95: p->p_tsize = 0; ! 96: p->p_dsize = 0; ! 97: p->p_ssize = 0; ! 98: u.u_tsize = 0; ! 99: u.u_dsize = 0; ! 100: u.u_ssize = 0; ! 101: } ! 102: ! 103: /* ! 104: * Pass virtual memory resources from p to q. ! 105: * P's u. area is up, q's is uq. Used internally ! 106: * when starting/ending a vfork(). ! 107: */ ! 108: vpassvm(p, q, up, uq, umap) ! 109: register struct proc *p, *q; ! 110: register struct user *up, *uq; ! 111: struct pte *umap; ! 112: { ! 113: ! 114: /* ! 115: * Pass fields related to vm sizes. ! 116: */ ! 117: uq->u_tsize = q->p_tsize = p->p_tsize; up->u_tsize = p->p_tsize = 0; ! 118: uq->u_dsize = q->p_dsize = p->p_dsize; up->u_dsize = p->p_dsize = 0; ! 119: uq->u_ssize = q->p_ssize = p->p_ssize; up->u_ssize = p->p_ssize = 0; ! 120: q->p_mmsize = p->p_mmsize; p->p_mmsize = 0; ! 121: ! 122: /* ! 123: * Pass proc table paging statistics. ! 124: */ ! 125: q->p_swrss = p->p_swrss; p->p_swrss = 0; ! 126: q->p_rssize = p->p_rssize; p->p_rssize = 0; ! 127: q->p_poip = p->p_poip; p->p_poip = 0; ! 128: ! 129: /* ! 130: * Relink text segment. ! 131: */ ! 132: q->p_textp = p->p_textp; ! 133: xrepl(p, q); ! 134: p->p_textp = 0; ! 135: ! 136: /* ! 137: * Pass swap space maps. ! 138: */ ! 139: uq->u_dmap = up->u_dmap; up->u_dmap = zdmap; ! 140: uq->u_smap = up->u_smap; up->u_smap = zdmap; ! 141: ! 142: /* ! 143: * Pass u. paging statistics. ! 144: */ ! 145: uq->u_outime = up->u_outime; up->u_outime = 0; ! 146: uq->u_ru = up->u_ru; ! 147: bzero((caddr_t)&up->u_ru, sizeof (struct rusage)); ! 148: uq->u_cru = up->u_cru; ! 149: bzero((caddr_t)&up->u_cru, sizeof (struct rusage)); ! 150: ! 151: /* ! 152: * And finally, pass the page tables themselves. ! 153: * On return we are running on the other set of ! 154: * page tables, but still with the same u. area. ! 155: */ ! 156: vpasspt(p, q, up, uq, umap); ! 157: #ifdef MAPMEM ! 158: /* ! 159: * Exchange mapped memory resources. ! 160: */ ! 161: if (up->u_mmap) ! 162: mmvfork(up, uq); ! 163: #endif ! 164: } ! 165: ! 166: /* ! 167: * Change the size of the data+stack regions of the process. ! 168: * If the size is shrinking, it's easy-- just release virtual memory. ! 169: * If it's growing, initalize new page table entries as ! 170: * 'zero fill on demand' pages. ! 171: */ ! 172: expand(change, region) ! 173: int change, region; ! 174: { ! 175: register struct proc *p; ! 176: #if defined(vax) ! 177: register struct pte *base, *p0, *p1; ! 178: int p0lr, p1lr; ! 179: #endif ! 180: #if defined(tahoe) ! 181: register struct pte *base, *p0, *p2; ! 182: int p0lr, p2lr; ! 183: #endif ! 184: #if defined(hp300) || defined(i386) ! 185: register struct pte *base; ! 186: int p0lr, p1lr; ! 187: #endif ! 188: struct pte proto; ! 189: struct pte *base0; ! 190: segsz_t ods, oss; ! 191: int size; ! 192: u_int v; ! 193: ! 194: p = u.u_procp; ! 195: if (change == 0) ! 196: return; ! 197: if (change % CLSIZE) ! 198: panic("expand"); ! 199: ! 200: #ifdef PGINPROF ! 201: vmsizmon(); ! 202: #endif ! 203: ! 204: /* ! 205: * Update the sizes to reflect the change. Note that we may ! 206: * swap as a result of a ptexpand, but this will work, because ! 207: * the routines which swap out will get the current text and data ! 208: * sizes from the arguments they are passed, and when the process ! 209: * resumes the lengths in the proc structure are used to ! 210: * build the new page tables. ! 211: */ ! 212: ods = u.u_dsize; ! 213: oss = u.u_ssize; ! 214: if (region == 0) { ! 215: v = dptov(p, change > 0 ? p->p_dsize : p->p_dsize+change); ! 216: p->p_dsize += change; ! 217: u.u_dsize += change; ! 218: } else { ! 219: v = sptov(p, change > 0 ? p->p_ssize-1+change : p->p_ssize-1); ! 220: p->p_ssize += change; ! 221: u.u_ssize += change; ! 222: } ! 223: ! 224: /* ! 225: * Compute the end of the text+data regions and the beginning ! 226: * of the stack region in the page tables, ! 227: * and expand the page tables if necessary. ! 228: */ ! 229: #if defined(vax) ! 230: p0 = u.u_pcb.pcb_p0br + (u.u_pcb.pcb_p0lr&~AST_CLR); ! 231: p1 = u.u_pcb.pcb_p1br + (u.u_pcb.pcb_p1lr&~PME_CLR); ! 232: if (change > p1 - p0) ! 233: ptexpand(clrnd(ctopt(change - (p1 - p0))), ods, p->p_mmsize, oss); ! 234: #endif ! 235: #if defined(tahoe) ! 236: p0 = u.u_pcb.pcb_p0br + u.u_pcb.pcb_p0lr; ! 237: p2 = u.u_pcb.pcb_p2br + u.u_pcb.pcb_p2lr; ! 238: if (change > p2 - p0) ! 239: ptexpand(clrnd(ctopt(change - (p2 - p0))), ods, p->p_mmsize, oss); ! 240: #endif ! 241: #if defined(hp300) || defined(i386) ! 242: size = ptsize(p) - u.u_pcb.pcb_szpt; ! 243: if (size > 0) ! 244: ptexpand(size, ods, p->p_mmsize, oss); ! 245: #endif ! 246: /* PTEXPAND SHOULD GIVE BACK EXCESS PAGE TABLE PAGES */ ! 247: ! 248: /* ! 249: * Compute the base of the allocated/freed region. ! 250: */ ! 251: #if defined(vax) ! 252: p0lr = u.u_pcb.pcb_p0lr&~AST_CLR; ! 253: p1lr = u.u_pcb.pcb_p1lr&~PME_CLR; ! 254: #endif ! 255: #if defined(tahoe) ! 256: p0lr = u.u_pcb.pcb_p0lr; ! 257: p2lr = u.u_pcb.pcb_p2lr; ! 258: #endif ! 259: #if defined(hp300) || defined(i386) ! 260: p0lr = u.u_pcb.pcb_p0lr; ! 261: p1lr = u.u_pcb.pcb_p1lr; ! 262: #endif ! 263: if (region == 0) { ! 264: #ifdef MAPMEM ! 265: size = dptov(u.u_procp, ods); ! 266: #else ! 267: size = p0lr; ! 268: #endif ! 269: base = u.u_pcb.pcb_p0br + size + (change > 0 ? 0 : change); ! 270: } else { ! 271: #if defined(vax) || defined(hp300) || defined(i386) ! 272: size = p1lr; ! 273: base = u.u_pcb.pcb_p1br + size - (change > 0 ? change : 0); ! 274: #endif ! 275: #if defined(tahoe) ! 276: size = p2lr; ! 277: base = u.u_pcb.pcb_p2br + size - (change > 0 ? change : 0); ! 278: #endif ! 279: } ! 280: ! 281: /* ! 282: * If we shrank, give back the virtual memory. ! 283: */ ! 284: if (change < 0) ! 285: p->p_rssize -= vmemfree(base, -change); ! 286: ! 287: /* ! 288: * Update the processor length registers and copies in the pcb. ! 289: */ ! 290: if (region == 0) { ! 291: if (u.u_procp->p_mmsize == 0) ! 292: setp0lr(size + change); ! 293: } else ! 294: #if defined(vax) || defined(hp300) || defined(i386) ! 295: setp1lr(size - change); ! 296: #endif ! 297: #if defined(tahoe) ! 298: setp2lr(size - change); ! 299: #endif ! 300: ! 301: /* ! 302: * If shrinking, clear pte's, otherwise ! 303: * initialize zero fill on demand pte's. ! 304: */ ! 305: *(int *)&proto = PG_UW; ! 306: if (change < 0) ! 307: change = -change; ! 308: else { ! 309: proto.pg_fod = 1; ! 310: ((struct fpte *)&proto)->pg_fileno = PG_FZERO; ! 311: cnt.v_nzfod += change; ! 312: } ! 313: base0 = base; ! 314: size = change; ! 315: while (--change >= 0) ! 316: *base++ = proto; ! 317: ! 318: /* ! 319: * We changed mapping for the current process, ! 320: * so must update the hardware translation ! 321: */ ! 322: newptes(base0, v, size); ! 323: } ! 324: ! 325: /* ! 326: * Create a duplicate copy of the current process ! 327: * in process slot p, which has been partially initialized ! 328: * by newproc(). ! 329: * ! 330: * Could deadlock here if two large proc's get page tables ! 331: * and then each gets part of his UPAGES if they then have ! 332: * consumed all the available memory. This can only happen when ! 333: * USRPTSIZE + UPAGES * NPROC > maxmem ! 334: * which is impossible except on systems with tiny real memories, ! 335: * when large procs stupidly fork() instead of vfork(). ! 336: */ ! 337: procdup(p, isvfork) ! 338: register struct proc *p; ! 339: { ! 340: ! 341: /* ! 342: * Allocate page tables for new process, waiting ! 343: * for memory to be free. ! 344: */ ! 345: while (vgetpt(p, vmemall) == 0) { ! 346: kmapwnt++; ! 347: sleep((caddr_t)kernelmap, PSWP+4); ! 348: } ! 349: /* ! 350: * Snapshot the current u. area pcb and get a u. ! 351: * for the new process, a copy of our u. ! 352: */ ! 353: resume(pcbb(u.u_procp)); ! 354: (void) vgetu(p, vmemall, Forkmap, &forkutl, &u); ! 355: #if defined(tahoe) ! 356: /* ! 357: * Define new cache data key. ! 358: */ ! 359: ckey_cnt[forkutl.u_procp->p_ckey]++; ! 360: forkutl.u_procp->p_dkey = getdatakey(); ! 361: forkutl.u_pcb.pcb_savacc.faddr = (float *)NULL; ! 362: #endif ! 363: ! 364: /* ! 365: * Arrange for a non-local goto when the new process ! 366: * is started, to resume here, returning nonzero from setjmp. ! 367: */ ! 368: forkutl.u_pcb.pcb_sswap = (int *)&u.u_ssave; ! 369: if (savectx(&forkutl.u_ssave)) { ! 370: #ifdef MAPMEM ! 371: if ((u.u_procp->p_flag & SVFORK) == 0 && u.u_mmap) ! 372: (void) mmfork((struct user *)0, &u); ! 373: #endif ! 374: /* ! 375: * Return 1 in child. ! 376: */ ! 377: return (1); ! 378: } ! 379: ! 380: /* ! 381: * If the new process is being created in vfork(), then ! 382: * exchange vm resources with it. We want to end up with ! 383: * just a u. area and an empty p0 region, so initialize the ! 384: * prototypes in the other area before the exchange. ! 385: */ ! 386: if (isvfork) { ! 387: #if defined(vax) ! 388: forkutl.u_pcb.pcb_p0lr = u.u_pcb.pcb_p0lr & AST_CLR; ! 389: forkutl.u_pcb.pcb_p1lr = P1PAGES - HIGHPAGES; ! 390: #endif ! 391: #if defined(tahoe) ! 392: forkutl.u_pcb.pcb_p0lr = u.u_pcb.pcb_p0lr; ! 393: forkutl.u_pcb.pcb_p1lr = 0; ! 394: forkutl.u_pcb.pcb_p2lr = P2PAGES - HIGHPAGES; ! 395: #endif ! 396: #if defined(hp300) || defined(i386) ! 397: forkutl.u_pcb.pcb_p0lr = 0; ! 398: forkutl.u_pcb.pcb_p1lr = P1PAGES - HIGHPAGES; ! 399: #endif ! 400: vpassvm(u.u_procp, p, &u, &forkutl, Forkmap); ! 401: /* ! 402: * Return 0 in parent. ! 403: */ ! 404: return (0); ! 405: } ! 406: /* ! 407: * A real fork; clear vm statistics of new process ! 408: * and link into the new text segment. ! 409: * Equivalent things happen during vfork() in vpassvm(). ! 410: */ ! 411: bzero((caddr_t)&forkutl.u_ru, sizeof (struct rusage)); ! 412: bzero((caddr_t)&forkutl.u_cru, sizeof (struct rusage)); ! 413: forkutl.u_dmap = u.u_cdmap; ! 414: forkutl.u_smap = u.u_csmap; ! 415: forkutl.u_outime = 0; ! 416: ! 417: /* ! 418: * Attach to the text segment. ! 419: */ ! 420: if (p->p_textp) { ! 421: p->p_textp->x_count++; ! 422: xlink(p); ! 423: } ! 424: ! 425: #ifdef MAPMEM ! 426: /* ! 427: * We do this before duplicating the address space since vmdup() ! 428: * might block causing Forkmap/forkutl to become invalid ! 429: */ ! 430: if (u.u_mmap) ! 431: (void) mmfork(&u, &forkutl); ! 432: #endif ! 433: /* ! 434: * Duplicate data and stack space of current process ! 435: * in the new process. ! 436: */ ! 437: vmdup(p, dptopte(p, 0), dptov(p, 0), p->p_dsize, CDATA); ! 438: vmdup(p, sptopte(p, p->p_ssize - 1), sptov(p, p->p_ssize - 1), p->p_ssize, CSTACK); ! 439: ! 440: /* ! 441: * Return 0 in parent. ! 442: */ ! 443: return (0); ! 444: } ! 445: ! 446: vmdup(p, pte, v, count, type) ! 447: struct proc *p; ! 448: register struct pte *pte; ! 449: register unsigned v; ! 450: register segsz_t count; ! 451: int type; ! 452: { ! 453: register struct pte *opte = vtopte(u.u_procp, v); ! 454: register int i; ! 455: register struct cmap *c; ! 456: ! 457: while (count != 0) { ! 458: count -= CLSIZE; ! 459: if (opte->pg_fod) { ! 460: v += CLSIZE; ! 461: for (i = 0; i < CLSIZE; i++) ! 462: *(int *)pte++ = *(int *)opte++; ! 463: continue; ! 464: } ! 465: opte += CLSIZE; ! 466: (void) vmemall(pte, CLSIZE, p, type); ! 467: p->p_rssize += CLSIZE; ! 468: for (i = 0; i < CLSIZE; i++) { ! 469: copyseg((caddr_t)ctob(v+i), (pte+i)->pg_pfnum); ! 470: *(int *)(pte+i) |= (PG_V|PG_M) + PG_UW; ! 471: } ! 472: v += CLSIZE; ! 473: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 474: MUNLOCK(c); ! 475: pte += CLSIZE; ! 476: } ! 477: p->p_flag |= SPTECHG; ! 478: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.