|
|
1.1 ! root 1: /* vmpt.c 4.11 81/04/15 */ ! 2: ! 3: #include "sys/param.h" ! 4: #include "sys/systm.h" ! 5: #include "sys/user.h" ! 6: #include "sys/proc.h" ! 7: #include "sys/map.h" ! 8: #include "sys/mtpr.h" ! 9: #include "sys/pte.h" ! 10: #include "sys/cmap.h" ! 11: #include "sys/vm.h" ! 12: #include "sys/buf.h" ! 13: #include "sys/text.h" ! 14: ! 15: extern struct map kernelmap[], swapmap[]; ! 16: ! 17: /* ! 18: * Get page tables for process p. Allocator ! 19: * for memory is argument; process must be locked ! 20: * from swapping if vmemall is used; if memall is ! 21: * used, call will return w/o waiting for memory. ! 22: * In any case an error return results if no user ! 23: * page table space is available. ! 24: */ ! 25: vgetpt(p, pmemall) ! 26: register struct proc *p; ! 27: int (*pmemall)(); ! 28: { ! 29: register int a; ! 30: register int i; ! 31: ! 32: if (p->p_szpt == 0) ! 33: panic("vgetpt"); ! 34: /* ! 35: * Allocate space in the kernel map for this process. ! 36: * Then allocate page table pages, and initialize the ! 37: * process' p0br and addr pointer to be the kernel ! 38: * virtual addresses of the base of the page tables and ! 39: * the pte for the process pcb (at the base of the u.). ! 40: */ ! 41: a = rmalloc(kernelmap, p->p_szpt); ! 42: if (a == 0) ! 43: return (0); ! 44: if ((*pmemall)(&Usrptmap[a], p->p_szpt, p, CSYS) == 0) { ! 45: kmfree(p->p_szpt, a); ! 46: return (0); ! 47: } ! 48: p->p_p0br = kmxtob(a); ! 49: p->p_addr = uaddr(p); ! 50: /* ! 51: * Now validate the system page table entries for the ! 52: * user page table pages, flushing old translations ! 53: * for these kernel virtual addresses. Clear the new ! 54: * page table pages for clean post-mortems. ! 55: */ ! 56: vmaccess(&Usrptmap[a], (caddr_t)p->p_p0br, p->p_szpt); ! 57: for (i = 0; i < p->p_szpt; i++) ! 58: clearseg(Usrptmap[a + i].pg_pfnum); ! 59: return (1); ! 60: } ! 61: ! 62: /* ! 63: * Initialize text portion of page table. ! 64: */ ! 65: vinitpt(p) ! 66: struct proc *p; ! 67: { ! 68: register struct text *xp; ! 69: register struct proc *q; ! 70: register struct pte *pte; ! 71: register int i; ! 72: struct pte proto; ! 73: ! 74: xp = p->p_textp; ! 75: if (xp == 0) ! 76: return; ! 77: pte = tptopte(p, 0); ! 78: /* ! 79: * If there is another instance of same text in core ! 80: * then just copy page tables from other process. ! 81: */ ! 82: if (q = xp->x_caddr) { ! 83: bcopy((caddr_t)tptopte(q, 0), (caddr_t)pte, ! 84: (unsigned) (sizeof(struct pte) * xp->x_size)); ! 85: goto done; ! 86: } ! 87: /* ! 88: * Initialize text page tables, zfod if we are loading ! 89: * the text now; unless the process is demand loaded, ! 90: * this will suffice as the text will henceforth either be ! 91: * read from a file or demand paged in. ! 92: */ ! 93: *(int *)&proto = PG_URKR; ! 94: if (xp->x_flag & XLOAD) { ! 95: proto.pg_fod = 1; ! 96: ((struct fpte *)&proto)->pg_source = PG_FZERO; ! 97: } ! 98: for (i = 0; i < xp->x_size; i++) ! 99: *pte++ = proto; ! 100: if ((xp->x_flag & XPAGI) == 0) ! 101: goto done; ! 102: /* ! 103: * Text is demand loaded. If process is not loaded (i.e. being ! 104: * swapped in) then retrieve page tables from swap area. Otherwise ! 105: * this is the first time and we must initialize the page tables ! 106: * from the blocks in the file system. ! 107: */ ! 108: if (xp->x_flag & XLOAD) ! 109: vinifod((struct fpte *)tptopte(p, 0), xp->x_iptr, ! 110: (daddr_t)1, xp->x_size); ! 111: else ! 112: swap(p, xp->x_ptdaddr, (caddr_t)tptopte(p, 0), ! 113: xp->x_size * sizeof (struct pte), B_READ, ! 114: B_PAGET, swapdev, 0); ! 115: done: ! 116: /* ! 117: * In the case where we are overlaying ourself with new page ! 118: * table entries, old user-space translations should be flushed. ! 119: */ ! 120: if (p == u.u_procp) ! 121: mtpr(TBIA, 0); ! 122: } ! 123: ! 124: /* ! 125: * Update the page tables of all processes linked ! 126: * to a particular text segment, by distributing ! 127: * dpte to the the text page at virtual frame v. ! 128: * ! 129: * Note that invalidation in the translation buffer for ! 130: * the current process is the responsibility of the caller. ! 131: */ ! 132: distpte(xp, tp, dpte) ! 133: struct text *xp; ! 134: register clicks_t tp; ! 135: register struct pte *dpte; ! 136: { ! 137: register struct proc *p; ! 138: register struct pte *pte; ! 139: register int i; ! 140: ! 141: for (p = xp->x_caddr; p; p = p->p_xlink) { ! 142: pte = tptopte(p, tp); ! 143: if (pte != dpte) ! 144: for (i = 0; i < CLSIZE; i++) ! 145: pte[i] = dpte[i]; ! 146: } ! 147: } ! 148: ! 149: /* ! 150: * Release page tables of process p. ! 151: */ ! 152: vrelpt(p) ! 153: register struct proc *p; ! 154: { ! 155: register int a; ! 156: ! 157: if (p->p_szpt == 0) ! 158: return; ! 159: a = btokmx(p->p_p0br); ! 160: (void) vmemfree(&Usrptmap[a], p->p_szpt); ! 161: kmfree(p->p_szpt, a); ! 162: } ! 163: ! 164: /* ! 165: * Compute number of pages to be allocated to the u. area ! 166: * and data and stack area page tables, which are stored on the ! 167: * disk immediately after the u. area. ! 168: */ ! 169: vusize(p) ! 170: register struct proc *p; ! 171: { ! 172: register int tsz = p->p_tsize / NPTEPG; ! 173: ! 174: /* ! 175: * We do not need page table space on the disk for page ! 176: * table pages wholly containing text. This is well ! 177: * understood in the code in vmswap.c. ! 178: */ ! 179: return (clrnd(UPAGES + ! 180: clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES)) - tsz)); ! 181: } ! 182: ! 183: /* ! 184: * Get u area for process p. If a old u area is given, ! 185: * then copy the new area from the old, else ! 186: * swap in as specified in the proc structure. ! 187: * ! 188: * Since argument map/newu is potentially shared ! 189: * when an old u. is provided we have to be careful not ! 190: * to block after beginning to use them in this case. ! 191: * (This is not true when called from swapin() with no old u.) ! 192: */ ! 193: vgetu(p, palloc, map, newu, oldu) ! 194: register struct proc *p; ! 195: int (*palloc)(); ! 196: register struct pte *map; ! 197: register struct user *newu; ! 198: struct user *oldu; ! 199: { ! 200: register int i; ! 201: ! 202: if ((*palloc)(p->p_addr, clrnd(UPAGES), p, CSYS) == 0) ! 203: return (0); ! 204: /* ! 205: * New u. pages are to be accessible in map/newu as well ! 206: * as in process p's virtual memory. ! 207: */ ! 208: for (i = 0; i < UPAGES; i++) { ! 209: map[i] = p->p_addr[i]; ! 210: *(int *)(p->p_addr + i) |= PG_URKW | PG_V; ! 211: } ! 212: setredzone(p->p_addr, (caddr_t)0); ! 213: vmaccess(map, (caddr_t)newu, UPAGES); ! 214: /* ! 215: * New u.'s come from forking or inswap. ! 216: */ ! 217: if (oldu) { ! 218: bcopy((caddr_t)oldu, (caddr_t)newu, UPAGES * NBPG); ! 219: newu->u_procp = p; ! 220: } else { int tf = 0; ! 221: swap(p, p->p_swaddr, (caddr_t)0, ctob(UPAGES), ! 222: B_READ, B_UAREA, swapdev, 0); ! 223: /*if (newu->u_pcb.pcb_ssp != -1 || newu->u_pcb.pcb_esp != -1 || ! 224: newu->u_tsize != p->p_tsize || newu->u_dsize != p->p_dsize || ! 225: newu->u_ssize != p->p_ssize || newu->u_procp != p) ! 226: panic("vgetu");*/ ! 227: if(newu->u_pcb.pcb_ssp != -1) tf |= 1; ! 228: if(newu->u_pcb.pcb_esp != -1) tf |= 2; ! 229: if(newu->u_tsize != p->p_tsize) tf |= 4; ! 230: if(newu->u_dsize != p->p_dsize) tf |= 8; ! 231: if(newu->u_ssize != p->p_ssize) tf |= 16; ! 232: if(newu->u_procp != p) tf |= 32; ! 233: if(tf) { ! 234: printf("vgetu %d ", tf); ! 235: panic("vgetu"); ! 236: } ! 237: } ! 238: /* ! 239: * Initialize the pcb copies of the p0 and p1 region bases and ! 240: * software page table size from the information in the proc structure. ! 241: */ ! 242: newu->u_pcb.pcb_p0br = p->p_p0br; ! 243: newu->u_pcb.pcb_p1br = p->p_p0br + p->p_szpt * NPTEPG - P1TOP; ! 244: newu->u_pcb.pcb_szpt = p->p_szpt; ! 245: return (1); ! 246: } ! 247: ! 248: /* ! 249: * Release swap space for a u. area. ! 250: */ ! 251: vrelswu(p) ! 252: struct proc *p; ! 253: { ! 254: ! 255: rmfree(swapmap, ctod(vusize(p)), p->p_swaddr); ! 256: /* p->p_swaddr = 0; */ /* leave for post-mortems */ ! 257: } ! 258: ! 259: /* ! 260: * Get swap space for a u. area. ! 261: */ ! 262: vgetswu(p) ! 263: struct proc *p; ! 264: { ! 265: ! 266: p->p_swaddr = srmalloc(swapmap, ctod(vusize(p))); ! 267: return (p->p_swaddr); ! 268: } ! 269: ! 270: /* ! 271: * Release u. area, swapping it out if desired. ! 272: * ! 273: * Note: we run on the old u. after it is released into swtch(), ! 274: * and are safe because nothing can happen at interrupt time. ! 275: */ ! 276: vrelu(p, swapu) ! 277: register struct proc *p; ! 278: { ! 279: register int i; ! 280: struct pte uu[UPAGES]; ! 281: ! 282: if (swapu) ! 283: swap(p, p->p_swaddr, (caddr_t)0, ctob(UPAGES), ! 284: B_WRITE, B_UAREA, swapdev, 0); ! 285: for (i = 0; i < UPAGES; i++) ! 286: uu[i] = p->p_addr[i]; ! 287: (void) vmemfree(uu, clrnd(UPAGES)); ! 288: } ! 289: ! 290: #ifdef unneeded ! 291: int ptforceswap; ! 292: #endif ! 293: /* ! 294: * Expand a page table, assigning new kernel virtual ! 295: * space and copying the page table entries over both ! 296: * in the system map and as necessary in the user page table space. ! 297: */ ! 298: ptexpand(change) ! 299: register int change; ! 300: { ! 301: register struct pte *p1, *p2; ! 302: register int i; ! 303: register int spages, ss = P1TOP - mfpr(P1LR); ! 304: register int kold = btokmx((struct pte *)mfpr(P0BR)); ! 305: int knew, tdpages; ! 306: int szpt = u.u_pcb.pcb_szpt; ! 307: int s; ! 308: ! 309: if (change <= 0 || change % CLSIZE) ! 310: panic("ptexpand 1"); ! 311: /* ! 312: * Change is the number of new page table pages needed. ! 313: * Kold is the old index in the kernelmap of the page tables. ! 314: * Allocate a new kernel map segment of size szpt+change for ! 315: * the page tables, and the new page table pages in the ! 316: * middle of this new region. ! 317: */ ! 318: top: ! 319: if ((knew=rmalloc(kernelmap, szpt+change)) == 0) ! 320: goto bad; ! 321: spages = ss/NPTEPG; ! 322: tdpages = szpt - spages; ! 323: if (memall(&Usrptmap[knew+tdpages], change, u.u_procp, CSYS) == 0) { ! 324: kmfree(szpt+change, knew); ! 325: goto bad; ! 326: } ! 327: /* ! 328: * Spages pages of u.+stack page tables go over unchanged. ! 329: * Tdpages of text+data page table may contain a few stack ! 330: * pages which need to go in one of the newly allocated pages; ! 331: * this is a rough cut. ! 332: */ ! 333: kmcopy(knew, kold, tdpages); ! 334: kmcopy(knew+tdpages+change, kold+tdpages, spages); ! 335: ! 336: /* ! 337: * Validate and clear the newly allocated page table pages in the ! 338: * center of the new region of the kernelmap. ! 339: * Then flush translation since we changed ! 340: * the kernel page tables. ! 341: */ ! 342: i = knew + tdpages; ! 343: p1 = &Usrptmap[i]; ! 344: p2 = p1 + change; ! 345: while (p1 < p2) { ! 346: *(int *)p1 |= PG_V | PG_KW; ! 347: clearseg(p1->pg_pfnum); ! 348: p1++; ! 349: i++; ! 350: } ! 351: mtpr(TBIA, 0); ! 352: ! 353: /* ! 354: * Move the stack or u. pte's which are before the newly ! 355: * allocated pages into the last of the newly allocated pages. ! 356: * They are taken from the end of the current p1 region, ! 357: * and moved to the end of the new p1 region. There are ! 358: * ss % NPTEPG such pte's. ! 359: */ ! 360: p1 = (struct pte *)mfpr(P1BR) + mfpr(P1LR); ! 361: p2 = kmxtob(knew+szpt+change) - ss; ! 362: for (i = ss - NPTEPG*spages; i != 0; i--) ! 363: *p2++ = *p1++; ! 364: ! 365: /* ! 366: * Now switch to the new page tables. ! 367: */ ! 368: mtpr(TBIA, 0); /* paranoid */ ! 369: s = spl7(); /* conservative */ ! 370: u.u_procp->p_p0br = kmxtob(knew); ! 371: u.u_pcb.pcb_p0br = kmxtob(knew); ! 372: u.u_pcb.pcb_p1br = kmxtob(knew+szpt+change) - P1TOP; ! 373: u.u_pcb.pcb_szpt += change; ! 374: u.u_procp->p_szpt += change; ! 375: u.u_procp->p_addr = uaddr(u.u_procp); ! 376: mtpr(P0BR, u.u_procp->p_p0br); ! 377: mtpr(P1BR, u.u_pcb.pcb_p1br); ! 378: mtpr(TBIA, 0); ! 379: splx(s); ! 380: ! 381: /* ! 382: * Finally, free old kernelmap. ! 383: */ ! 384: if (szpt) ! 385: kmfree(szpt, kold); ! 386: return; ! 387: ! 388: bad: ! 389: /* ! 390: * Swap out the process so that the unavailable ! 391: * resource will be allocated upon swapin. ! 392: * ! 393: * When resume is executed for the process, ! 394: * here is where it will resume. ! 395: */ ! 396: resume(pcbb(u.u_procp)); ! 397: if (savectx(u.u_ssav)) ! 398: return; ! 399: if (swapout(u.u_procp, (clicks_t)(mfpr(P0LR) - u.u_tsize), ss - UPAGES) == 0) { ! 400: /* ! 401: * No space to swap... it is inconvenient to try ! 402: * to exit, so just wait a bit and hope something ! 403: * turns up. Could deadlock here. ! 404: * ! 405: * SOMEDAY REFLECT ERROR BACK THROUGH expand TO CALLERS ! 406: * (grow, sbreak) SO CAN'T DEADLOCK HERE. ! 407: */ ! 408: printf(":"); ! 409: sleep((caddr_t)&lbolt, PRIBIO); ! 410: goto top; ! 411: } ! 412: /* ! 413: * Set SSWAP bit, so that when process is swapped back in ! 414: * swapin will set u.u_pcb.pcb_sswap to u_sswap and force a ! 415: * return from the setjmp() above. ! 416: */ ! 417: u.u_procp->p_flag |= SSWAP; ! 418: swtch(); ! 419: /* no return */ ! 420: } ! 421: ! 422: kmcopy(to, from, count) ! 423: register int to; ! 424: int from; ! 425: register int count; ! 426: { ! 427: register struct pte *tp = &Usrptmap[to]; ! 428: register struct pte *fp = &Usrptmap[from]; ! 429: ! 430: while (count != 0) { ! 431: *tp++ = *fp++; ! 432: to++; ! 433: count--; ! 434: } ! 435: } ! 436: ! 437: kmfree(addr, size) ! 438: int addr, size; ! 439: { ! 440: rmfree(kernelmap, addr, size); ! 441: if (kmapwnt) { ! 442: kmapwnt = 0; ! 443: wakeup((caddr_t)kernelmap); ! 444: } ! 445: } ! 446: ! 447: #if NOTDEF ! 448: /* who calls this?? */ ! 449: /* ! 450: * Change protection codes of text segment. ! 451: * Have to flush translation buffer since this ! 452: * affect virtual memory mapping of current process. ! 453: */ ! 454: chgprot(p, addr, tprot) ! 455: struct proc *p; ! 456: caddr_t addr; ! 457: long tprot; ! 458: { ! 459: unsigned v; ! 460: int tp; ! 461: register struct pte *pte; ! 462: register struct cmap *c; ! 463: ! 464: v = clbase(btop(addr)); ! 465: if (!isatsv(p, v)) { ! 466: u.u_error = EFAULT; ! 467: return (0); ! 468: } ! 469: tp = vtotp(p, v); ! 470: pte = tptopte(p, tp); ! 471: if (pte->pg_fod == 0 && pte->pg_pfnum) { ! 472: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 473: if (c->c_blkno && c->c_mdev != MSWAPX) ! 474: munhash(c->c_mdev, (daddr_t)c->c_blkno); ! 475: } ! 476: *(int *)pte &= ~PG_PROT; ! 477: *(int *)pte |= tprot; ! 478: distcl(pte); ! 479: tbiscl(v); ! 480: return (1); ! 481: } ! 482: #endif ! 483: ! 484: settprot(okwrit) ! 485: int okwrit; ! 486: { ! 487: register int *ptaddr, i, prot; ! 488: ! 489: prot = okwrit ? PG_UW : PG_URKR; ! 490: ptaddr = (int *)mfpr(P0BR); ! 491: for (i = 0; i < u.u_tsize; i++) { ! 492: ptaddr[i] &= ~PG_PROT; ! 493: ptaddr[i] |= prot; ! 494: } ! 495: mtpr(TBIA, 0); ! 496: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.