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