|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 University of Utah. ! 3: * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * This code is derived from software contributed to Berkeley by ! 7: * the Systems Programming Group of the University of Utah Computer ! 8: * Science Department. ! 9: * ! 10: * Redistribution is only permitted until one year after the first shipment ! 11: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 12: * binary forms are permitted provided that: (1) source distributions retain ! 13: * this entire copyright notice and comment, and (2) distributions including ! 14: * binaries display the following acknowledgement: This product includes ! 15: * software developed by the University of California, Berkeley and its ! 16: * contributors'' in the documentation or other materials provided with the ! 17: * distribution and in all advertising materials mentioning features or use ! 18: * of this software. Neither the name of the University nor the names of ! 19: * its contributors may be used to endorse or promote products derived from ! 20: * this software without specific prior written permission. ! 21: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 22: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 23: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 24: * ! 25: * from: Utah $Hdr: vm_machdep.c 1.18 89/08/23$ ! 26: * ! 27: * @(#)vm_machdep.c 7.5 (Berkeley) 6/21/90 ! 28: */ ! 29: ! 30: #include "param.h" ! 31: #include "systm.h" ! 32: #include "user.h" ! 33: #include "proc.h" ! 34: #include "cmap.h" ! 35: #include "vm.h" ! 36: #include "text.h" ! 37: #include "malloc.h" ! 38: #include "buf.h" ! 39: ! 40: #include "cpu.h" ! 41: #include "pte.h" ! 42: ! 43: /* ! 44: * Set a red zone in the kernel stack after the u. area. ! 45: * We don't support a redzone right now. It really isn't clear ! 46: * that it is a good idea since, if the kernel stack were to roll ! 47: * into a write protected page, the processor would lock up (since ! 48: * it cannot create an exception frame) and we would get no useful ! 49: * post-mortem info. Currently, under the DEBUG option, we just ! 50: * check at every clock interrupt to see if the current k-stack has ! 51: * gone too far (i.e. into the "redzone" page) and if so, panic. ! 52: * Look at _lev6intr in locore.s for more details. ! 53: */ ! 54: /*ARGSUSED*/ ! 55: setredzone(pte, vaddr) ! 56: struct pte *pte; ! 57: caddr_t vaddr; ! 58: { ! 59: } ! 60: ! 61: /* ! 62: * Check for valid program size ! 63: * NB - Check data and data growth separately as they may overflow ! 64: * when summed together. ! 65: */ ! 66: chksize(ts, ids, uds, ss) ! 67: unsigned ts, ids, uds, ss; ! 68: { ! 69: extern unsigned maxtsize; ! 70: ! 71: if (ctob(ts) > maxtsize || ! 72: ctob(ids) > u.u_rlimit[RLIMIT_DATA].rlim_cur || ! 73: ctob(uds) > u.u_rlimit[RLIMIT_DATA].rlim_cur || ! 74: ctob(ids + uds) > u.u_rlimit[RLIMIT_DATA].rlim_cur || ! 75: ctob(ss) > u.u_rlimit[RLIMIT_STACK].rlim_cur) { ! 76: return (ENOMEM); ! 77: } ! 78: return (0); ! 79: } ! 80: ! 81: /*ARGSUSED*/ ! 82: newptes(pte, v, size) ! 83: struct pte *pte; ! 84: u_int v; ! 85: register int size; ! 86: { ! 87: register caddr_t a; ! 88: ! 89: #ifdef lint ! 90: pte = pte; ! 91: #endif ! 92: if (size >= 8) ! 93: TBIAU(); ! 94: else { ! 95: a = ptob(v); ! 96: while (size > 0) { ! 97: TBIS(a); ! 98: a += NBPG; ! 99: size--; ! 100: } ! 101: } ! 102: DCIU(); ! 103: } ! 104: ! 105: /* ! 106: * Change protection codes of text segment. ! 107: * Have to flush translation buffer since this ! 108: * affect virtual memory mapping of current process. ! 109: */ ! 110: chgprot(addr, tprot) ! 111: caddr_t addr; ! 112: long tprot; ! 113: { ! 114: unsigned v; ! 115: int tp; ! 116: register struct pte *pte; ! 117: register struct cmap *c; ! 118: ! 119: v = clbase(btop(addr)); ! 120: if (!isatsv(u.u_procp, v)) ! 121: return (EFAULT); ! 122: tp = vtotp(u.u_procp, v); ! 123: pte = tptopte(u.u_procp, tp); ! 124: if (pte->pg_fod == 0 && pte->pg_pfnum) { ! 125: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 126: if (c->c_blkno) ! 127: munhash(c->c_vp, (daddr_t)(u_long)c->c_blkno); ! 128: } ! 129: *(u_int *)pte &= ~PG_PROT; ! 130: *(u_int *)pte |= tprot; ! 131: TBIS(addr); ! 132: return (0); ! 133: } ! 134: ! 135: settprot(tprot) ! 136: long tprot; ! 137: { ! 138: register u_int *pte, i; ! 139: ! 140: pte = (u_int *)u.u_procp->p_p0br; ! 141: for (i = 0; i < u.u_tsize; i++, pte++) { ! 142: *pte &= ~PG_PROT; ! 143: *pte |= tprot; ! 144: } ! 145: TBIAU(); ! 146: } ! 147: ! 148: /* ! 149: * Simulate effect of VAX region length registers. ! 150: * The one case where we must do anything is if a region has shrunk. ! 151: * In that case we must invalidate all the PTEs for the no longer valid VAs. ! 152: */ ! 153: setptlr(region, nlen) ! 154: int nlen; ! 155: { ! 156: register struct pte *pte; ! 157: register int change; ! 158: int olen; ! 159: ! 160: if (region == 0) { ! 161: olen = u.u_pcb.pcb_p0lr; ! 162: u.u_pcb.pcb_p0lr = nlen; ! 163: } else { ! 164: olen = P1PAGES - u.u_pcb.pcb_p1lr; ! 165: u.u_pcb.pcb_p1lr = nlen; ! 166: nlen = P1PAGES - nlen; ! 167: } ! 168: if ((change = olen - nlen) <= 0) ! 169: return; ! 170: if (region == 0) ! 171: pte = u.u_pcb.pcb_p0br + u.u_pcb.pcb_p0lr; ! 172: else ! 173: pte = u.u_pcb.pcb_p1br + u.u_pcb.pcb_p1lr - change; ! 174: do { ! 175: *(u_int *)pte++ = PG_NV; ! 176: } while (--change); ! 177: /* short cut newptes */ ! 178: TBIAU(); ! 179: DCIU(); ! 180: } ! 181: ! 182: /* ! 183: * Map `size' bytes of physical memory starting at `paddr' into ! 184: * kernel VA space using PTEs starting at `pte'. Read/write and ! 185: * cache-inhibit status are specified by `prot'. ! 186: */ ! 187: physaccess(pte, paddr, size, prot) ! 188: register struct pte *pte; ! 189: caddr_t paddr; ! 190: register int size; ! 191: { ! 192: register u_int page; ! 193: ! 194: page = (u_int)paddr & PG_FRAME; ! 195: for (size = btoc(size); size; size--) { ! 196: *(int *)pte = PG_V | prot | page; ! 197: page += NBPG; ! 198: pte++; ! 199: } ! 200: TBIAS(); ! 201: } ! 202: ! 203: /* ! 204: * Move pages from one kernel virtual address to another. ! 205: * Both addresses are assumed to reside in the Sysmap, ! 206: * and size must be a multiple of CLSIZE. ! 207: */ ! 208: pagemove(from, to, size) ! 209: register caddr_t from, to; ! 210: int size; ! 211: { ! 212: register struct pte *fpte, *tpte; ! 213: ! 214: if (size % CLBYTES) ! 215: panic("pagemove"); ! 216: fpte = kvtopte(from); ! 217: tpte = kvtopte(to); ! 218: while (size > 0) { ! 219: *tpte++ = *fpte; ! 220: *(int *)fpte++ = PG_NV; ! 221: TBIS(from); ! 222: TBIS(to); ! 223: from += NBPG; ! 224: to += NBPG; ! 225: size -= NBPG; ! 226: } ! 227: } ! 228: ! 229: #ifdef KGDB ! 230: /* ! 231: * Change protections on kernel pages from addr to addr+size ! 232: * (presumably so debugger can plant a breakpoint). ! 233: * All addresses are assumed to reside in the Sysmap, ! 234: */ ! 235: chgkprot(addr, size, rw) ! 236: register caddr_t addr; ! 237: int size, rw; ! 238: { ! 239: register struct pte *pte; ! 240: ! 241: pte = &Sysmap[btop(addr)]; ! 242: while (size > 0) { ! 243: pte->pg_prot = rw == B_WRITE? 0 : 1; ! 244: TBIS(addr); ! 245: addr += NBPG; ! 246: size -= NBPG; ! 247: pte++; ! 248: } ! 249: } ! 250: #endif ! 251: ! 252: /* ! 253: * The probe[rw] routines should probably be redone in assembler ! 254: * for efficiency. ! 255: */ ! 256: prober(addr) ! 257: register u_int addr; ! 258: { ! 259: register int page; ! 260: register struct proc *p; ! 261: ! 262: if (addr >= USRSTACK) ! 263: return(0); ! 264: #ifdef HPUXCOMPAT ! 265: if (ISHPMMADDR(addr)) ! 266: addr = HPMMBASEADDR(addr); ! 267: #endif ! 268: page = btop(addr); ! 269: p = u.u_procp; ! 270: if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize)) ! 271: return(1); ! 272: #ifdef MAPMEM ! 273: if (page < dptov(p, p->p_dsize+p->p_mmsize) && ! 274: (*(int *)vtopte(p, page) & (PG_FOD|PG_V)) == (PG_FOD|PG_V)) ! 275: return(1); ! 276: #endif ! 277: return(0); ! 278: } ! 279: ! 280: probew(addr) ! 281: register u_int addr; ! 282: { ! 283: register int page; ! 284: register struct proc *p; ! 285: ! 286: if (addr >= USRSTACK) ! 287: return(0); ! 288: #ifdef HPUXCOMPAT ! 289: if (ISHPMMADDR(addr)) ! 290: addr = HPMMBASEADDR(addr); ! 291: #endif ! 292: page = btop(addr); ! 293: p = u.u_procp; ! 294: if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize)) ! 295: return((*(int *)vtopte(p, page) & PG_PROT) == PG_RW); ! 296: #ifdef MAPMEM ! 297: if (page < dptov(p, p->p_dsize+p->p_mmsize)) ! 298: return((*(int *)vtopte(p, page) & (PG_FOD|PG_V|PG_PROT)) ! 299: == (PG_FOD|PG_V|PG_RW)); ! 300: #endif ! 301: return(0); ! 302: } ! 303: ! 304: /* ! 305: * NB: assumes a physically contiguous kernel page table ! 306: * (makes life a LOT simpler). ! 307: */ ! 308: kernacc(addr, count, rw) ! 309: register caddr_t addr; ! 310: int count, rw; ! 311: { ! 312: register struct ste *ste; ! 313: register struct pte *pte; ! 314: register u_int ix, cnt; ! 315: extern long Syssize; ! 316: ! 317: if (count <= 0) ! 318: return(0); ! 319: ix = ((int)addr & SG_IMASK) >> SG_ISHIFT; ! 320: cnt = (((int)addr + count + (1<<SG_ISHIFT)-1) & SG_IMASK) >> SG_ISHIFT; ! 321: cnt -= ix; ! 322: for (ste = &Sysseg[ix]; cnt; cnt--, ste++) ! 323: /* should check SG_PROT, but we have no RO segments now */ ! 324: if (ste->sg_v == 0) ! 325: return(0); ! 326: ix = btop(addr); ! 327: cnt = btop(addr+count+NBPG-1); ! 328: if (cnt > (u_int)&Syssize) ! 329: return(0); ! 330: cnt -= ix; ! 331: for (pte = &Sysmap[ix]; cnt; cnt--, pte++) ! 332: if (pte->pg_v == 0 || (rw == B_WRITE && pte->pg_prot == 1)) ! 333: return(0); ! 334: return(1); ! 335: } ! 336: ! 337: useracc(addr, count, rw) ! 338: register caddr_t addr; ! 339: unsigned count; ! 340: { ! 341: register int (*func)(); ! 342: register u_int addr2; ! 343: extern int prober(), probew(); ! 344: ! 345: if (count <= 0) ! 346: return(0); ! 347: addr2 = (u_int) addr; ! 348: addr += count; ! 349: func = (rw == B_READ) ? prober : probew; ! 350: do { ! 351: if ((*func)(addr2) == 0) ! 352: return(0); ! 353: addr2 = (addr2 + NBPG) & ~PGOFSET; ! 354: } while (addr2 < (u_int)addr); ! 355: return(1); ! 356: } ! 357: ! 358: /* ! 359: * Convert kernel VA to physical address ! 360: */ ! 361: kvtop(addr) ! 362: register caddr_t addr; ! 363: { ! 364: register int pf; ! 365: ! 366: pf = Sysmap[btop(addr)].pg_pfnum; ! 367: if (pf == 0) ! 368: panic("kvtop: zero page frame"); ! 369: return((u_int)ptob(pf) + ((int)addr & PGOFSET)); ! 370: } ! 371: ! 372: struct ste * ! 373: vtoste(p, va) ! 374: register struct proc *p; ! 375: register u_int va; ! 376: { ! 377: register struct ste *ste; ! 378: ! 379: ste = (struct ste *)((u_int)p->p_p0br + p->p_szpt * NBPG); ! 380: return(ste + ((va & SG_IMASK) >> SG_ISHIFT)); ! 381: } ! 382: ! 383: initustp(p) ! 384: register struct proc *p; ! 385: { ! 386: return((int)Usrptmap[btokmx(p->p_p0br) + p->p_szpt].pg_pfnum); ! 387: } ! 388: ! 389: /* ! 390: * Initialize segment table to reflect PTEs in Usrptmap. ! 391: * Segment table address is given by Usrptmap index of p_szpt. ! 392: */ ! 393: initsegt(p) ! 394: register struct proc *p; ! 395: { ! 396: register int i, k, sz; ! 397: register struct ste *ste; ! 398: extern struct ste *vtoste(); ! 399: ! 400: k = btokmx(p->p_p0br); ! 401: ste = vtoste(p, 0); ! 402: /* text and data */ ! 403: sz = ctopt(p->p_tsize + p->p_dsize + p->p_mmsize); ! 404: for (i = 0; i < sz; i++, ste++) { ! 405: *(int *)ste = SG_RW | SG_V; ! 406: ste->sg_pfnum = Usrptmap[k++].pg_pfnum; ! 407: } ! 408: /* ! 409: * Bogus! The kernelmap may map unused PT pages ! 410: * (since we don't shrink PTs) so we need to skip over ! 411: * those STEs. We should really free the unused PT ! 412: * pages in expand(). ! 413: */ ! 414: sz += ctopt(p->p_ssize + HIGHPAGES); ! 415: if (sz < p->p_szpt) ! 416: k += p->p_szpt - sz; ! 417: /* hole */ ! 418: sz = NPTEPG - ctopt(p->p_ssize + HIGHPAGES); ! 419: for ( ; i < sz; i++, ste++) ! 420: *(int *)ste = SG_NV; ! 421: /* stack and u-area */ ! 422: sz = NPTEPG; ! 423: for ( ; i < sz; i++, ste++) { ! 424: *(int *)ste = SG_RW | SG_V; ! 425: ste->sg_pfnum = Usrptmap[k++].pg_pfnum; ! 426: } ! 427: } ! 428: ! 429: /* ! 430: * Allocate/free cache-inhibited physical memory. ! 431: * Assumes that malloc returns page aligned memory for requests which are ! 432: * a multiple of the page size. Hence, size must be such a multiple. ! 433: */ ! 434: caddr_t ! 435: cialloc(sz) ! 436: int sz; ! 437: { ! 438: caddr_t kva; ! 439: register int npg, *pte; ! 440: ! 441: if (sz & CLOFSET) ! 442: return(NULL); ! 443: kva = (caddr_t)malloc(sz, M_DEVBUF, M_NOWAIT); ! 444: if (kva) { ! 445: if (!claligned(kva)) ! 446: panic("cialloc"); ! 447: pte = (int *)kvtopte(kva); ! 448: npg = btoc(sz); ! 449: while (--npg >= 0) ! 450: *pte++ |= PG_CI; ! 451: TBIAS(); ! 452: } ! 453: return(kva); ! 454: } ! 455: ! 456: cifree(kva, sz) ! 457: caddr_t kva; ! 458: int sz; ! 459: { ! 460: register int npg, *pte; ! 461: ! 462: if (sz & CLOFSET) ! 463: panic("cifree"); ! 464: pte = (int *)kvtopte(kva); ! 465: npg = btoc(sz); ! 466: while (--npg >= 0) ! 467: *pte++ &= ~PG_CI; ! 468: TBIAS(); ! 469: free(kva, M_DEVBUF); ! 470: } ! 471: ! 472: extern char usrio[]; ! 473: extern struct pte Usriomap[]; ! 474: struct map *useriomap; ! 475: int usriowanted; ! 476: ! 477: /* ! 478: * Map an IO request into kernel virtual address space. Requests fall into ! 479: * one of five catagories: ! 480: * ! 481: * B_PHYS|B_UAREA: User u-area swap. ! 482: * Address is relative to start of u-area (p_addr). ! 483: * B_PHYS|B_PAGET: User page table swap. ! 484: * Address is a kernel VA in usrpt (Usrptmap). ! 485: * B_PHYS|B_DIRTY: Dirty page push. ! 486: * Address is a VA in proc2's address space. ! 487: * B_PHYS|B_PGIN: Kernel pagein of user pages. ! 488: * Address is VA in user's address space. ! 489: * B_PHYS: User "raw" IO request. ! 490: * Address is VA in user's address space. ! 491: * ! 492: * All requests are (re)mapped into kernel VA space via the useriomap ! 493: * (a name with only slightly more meaning than "kernelmap") ! 494: */ ! 495: vmapbuf(bp) ! 496: register struct buf *bp; ! 497: { ! 498: register int npf, a; ! 499: register caddr_t addr; ! 500: register struct pte *pte, *iopte; ! 501: register long flags = bp->b_flags; ! 502: struct proc *p; ! 503: int off, s; ! 504: ! 505: if ((flags & B_PHYS) == 0) ! 506: panic("vmapbuf"); ! 507: /* ! 508: * Find PTEs for the area to be mapped ! 509: */ ! 510: p = flags&B_DIRTY ? &proc[2] : bp->b_proc; ! 511: addr = bp->b_un.b_addr; ! 512: if (flags & B_UAREA) ! 513: pte = &p->p_addr[btop(addr)]; ! 514: else if (flags & B_PAGET) ! 515: pte = &Usrptmap[btokmx((struct pte *)addr)]; ! 516: else ! 517: pte = vtopte(p, btop(addr)); ! 518: /* ! 519: * Allocate some kernel PTEs and load them ! 520: */ ! 521: off = (int)addr & PGOFSET; ! 522: npf = btoc(bp->b_bcount + off); ! 523: s = splbio(); ! 524: while ((a = rmalloc(useriomap, npf)) == 0) { ! 525: usriowanted = 1; ! 526: sleep((caddr_t)useriomap, PSWP); ! 527: } ! 528: splx(s); ! 529: iopte = &Usriomap[a]; ! 530: bp->b_saveaddr = bp->b_un.b_addr; ! 531: addr = bp->b_un.b_addr = (caddr_t)(usrio + (a << PGSHIFT)) + off; ! 532: while (npf--) { ! 533: mapin(iopte, (u_int)addr, pte->pg_pfnum, PG_CI|PG_RW|PG_V); ! 534: iopte++, pte++; ! 535: addr += NBPG; ! 536: } ! 537: } ! 538: ! 539: /* ! 540: * Free the io map PTEs associated with this IO operation. ! 541: * We also invalidate the TLB entries and restore the original b_addr. ! 542: */ ! 543: vunmapbuf(bp) ! 544: register struct buf *bp; ! 545: { ! 546: register int a, npf; ! 547: register caddr_t addr = bp->b_un.b_addr; ! 548: register struct pte *pte; ! 549: int s; ! 550: ! 551: if ((bp->b_flags & B_PHYS) == 0) ! 552: panic("vunmapbuf"); ! 553: a = (int)(addr - usrio) >> PGSHIFT; ! 554: npf = btoc(bp->b_bcount + ((int)addr & PGOFSET)); ! 555: s = splbio(); ! 556: rmfree(useriomap, npf, a); ! 557: if (usriowanted) { ! 558: usriowanted = 0; ! 559: wakeup((caddr_t)useriomap); ! 560: } ! 561: splx(s); ! 562: pte = &Usriomap[a]; ! 563: while (npf--) { ! 564: *(int *)pte = PG_NV; ! 565: TBIS((caddr_t)addr); ! 566: addr += NBPG; ! 567: pte++; ! 568: } ! 569: bp->b_un.b_addr = bp->b_saveaddr; ! 570: bp->b_saveaddr = NULL; ! 571: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.