|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * Computer Consoles Inc. ! 7: * ! 8: * Redistribution is only permitted until one year after the first shipment ! 9: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 10: * binary forms are permitted provided that: (1) source distributions retain ! 11: * this entire copyright notice and comment, and (2) distributions including ! 12: * binaries display the following acknowledgement: This product includes ! 13: * software developed by the University of California, Berkeley and its ! 14: * contributors'' in the documentation or other materials provided with the ! 15: * distribution and in all advertising materials mentioning features or use ! 16: * of this software. Neither the name of the University nor the names of ! 17: * its contributors may be used to endorse or promote products derived from ! 18: * this software without specific prior written permission. ! 19: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 20: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 21: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 22: * ! 23: * @(#)vm_machdep.c 7.8 (Berkeley) 6/28/90 ! 24: */ ! 25: ! 26: #include "param.h" ! 27: #include "systm.h" ! 28: #include "user.h" ! 29: #include "proc.h" ! 30: #include "cmap.h" ! 31: #include "vm.h" ! 32: #include "text.h" ! 33: #include "kernel.h" ! 34: ! 35: #include "pte.h" ! 36: #include "cpu.h" ! 37: #include "mtpr.h" ! 38: ! 39: /* ! 40: * Set a red zone in the kernel stack after the u. area. ! 41: */ ! 42: setredzone(pte, vaddr) ! 43: register struct pte *pte; ! 44: caddr_t vaddr; ! 45: { ! 46: ! 47: pte += (sizeof (struct user) + NBPG - 1) / NBPG; ! 48: *(int *)pte &= ~PG_PROT; ! 49: *(int *)pte |= PG_URKR; ! 50: if (vaddr) ! 51: mtpr(TBIS, vaddr + sizeof (struct user) + NBPG - 1); ! 52: } ! 53: ! 54: /* ! 55: * Check for valid program size ! 56: * NB - Check data and data growth separately as they may overflow ! 57: * when summed together. ! 58: */ ! 59: chksize(ts, ids, uds, ss) ! 60: register unsigned ts, ids, uds, ss; ! 61: { ! 62: extern unsigned maxtsize; ! 63: ! 64: if (ctob(ts) > maxtsize || ! 65: ctob(ids) > u.u_rlimit[RLIMIT_DATA].rlim_cur || ! 66: ctob(uds) > u.u_rlimit[RLIMIT_DATA].rlim_cur || ! 67: ctob(ids + uds) > u.u_rlimit[RLIMIT_DATA].rlim_cur || ! 68: ctob(ss) > u.u_rlimit[RLIMIT_STACK].rlim_cur) { ! 69: return (ENOMEM); ! 70: } ! 71: return (0); ! 72: } ! 73: ! 74: /*ARGSUSED*/ ! 75: newptes(pte, v, size) ! 76: register struct pte *pte; ! 77: u_int v; ! 78: register int size; ! 79: { ! 80: register caddr_t a = ptob(v); ! 81: ! 82: #ifdef lint ! 83: pte = pte; ! 84: #endif ! 85: if (size >= 8) { ! 86: mtpr(TBIA, 0); ! 87: return; ! 88: } ! 89: while (size > 0) { ! 90: mtpr(TBIS, a); ! 91: a += NBPG; ! 92: size--; ! 93: } ! 94: } ! 95: ! 96: /* ! 97: * Change protection codes of text segment. ! 98: * Have to flush translation buffer since this ! 99: * affect virtual memory mapping of current process. ! 100: */ ! 101: chgprot(addr, tprot) ! 102: caddr_t addr; ! 103: long tprot; ! 104: { ! 105: unsigned v; ! 106: int tp; ! 107: register struct pte *pte; ! 108: register struct cmap *c; ! 109: ! 110: v = clbase(btop(addr)); ! 111: if (!isatsv(u.u_procp, v)) ! 112: return (EFAULT); ! 113: tp = vtotp(u.u_procp, v); ! 114: pte = tptopte(u.u_procp, tp); ! 115: if (pte->pg_fod == 0 && pte->pg_pfnum) { ! 116: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 117: if (c->c_blkno) ! 118: munhash(c->c_vp, (daddr_t)(u_long)c->c_blkno); ! 119: } ! 120: *(int *)pte &= ~PG_PROT; ! 121: *(int *)pte |= tprot; ! 122: distcl(pte); ! 123: tbiscl(v); ! 124: return (0); ! 125: } ! 126: ! 127: settprot(tprot) ! 128: long tprot; ! 129: { ! 130: register int *ptaddr, i; ! 131: ! 132: ptaddr = (int *)mfpr(P0BR); ! 133: for (i = 0; i < u.u_tsize; i++) { ! 134: ptaddr[i] &= ~PG_PROT; ! 135: ptaddr[i] |= tprot; ! 136: } ! 137: mtpr(TBIA, 0); ! 138: } ! 139: ! 140: #ifdef notdef ! 141: /* ! 142: * Rest are machine-dependent ! 143: */ ! 144: getmemc(addr) ! 145: caddr_t addr; ! 146: { ! 147: register int c; ! 148: struct pte savemap; ! 149: ! 150: savemap = mmap[0]; ! 151: *(int *)mmap = PG_V | PG_KR | btop(addr); ! 152: mtpr(TBIS, vmmap); ! 153: uncache(&vmmap[(int)addr & PGOFSET]); ! 154: c = *(char *)&vmmap[(int)addr & PGOFSET]; ! 155: mmap[0] = savemap; ! 156: mtpr(TBIS, vmmap); ! 157: return (c & 0377); ! 158: } ! 159: ! 160: putmemc(addr, val) ! 161: caddr_t addr; ! 162: { ! 163: struct pte savemap; ! 164: ! 165: savemap = mmap[0]; ! 166: *(int *)mmap = PG_V | PG_KW | btop(addr); ! 167: mtpr(TBIS, vmmap); ! 168: *(char *)&vmmap[(int)addr & PGOFSET] = val; ! 169: ! 170: mtpr(PADC, 0); ! 171: mtpr(PACC, 0); ! 172: ! 173: mmap[0] = savemap; ! 174: mtpr(TBIS, vmmap); ! 175: } ! 176: #endif ! 177: ! 178: /* ! 179: * Move pages from one kernel virtual address to another. ! 180: * Both addresses are assumed to reside in the Sysmap, ! 181: * and size must be a multiple of CLSIZE. ! 182: */ ! 183: pagemove(from, to, size) ! 184: register caddr_t from, to; ! 185: int size; ! 186: { ! 187: register struct pte *fpte, *tpte; ! 188: ! 189: if (size % CLBYTES) ! 190: panic("pagemove"); ! 191: fpte = kvtopte(from); ! 192: tpte = kvtopte(to); ! 193: while (size > 0) { ! 194: *tpte++ = *fpte; ! 195: *(int *)fpte++ = 0; ! 196: mtpr(TBIS, from); ! 197: mtpr(TBIS, to); ! 198: mtpr(P1DC, to); /* purge !! */ ! 199: from += NBPG; ! 200: to += NBPG; ! 201: size -= NBPG; ! 202: } ! 203: } ! 204: ! 205: /* ! 206: * Code and data key management routines. ! 207: * ! 208: * The array ckey_cnt maintains the count of processes currently ! 209: * sharing each code key. The array ckey_cache maintains a record ! 210: * of all code keys used since the last flush of the code cache. ! 211: * Such keys may not be reused, even if unreferenced, until ! 212: * the cache is flushed. The data cache key handling is analogous. ! 213: * The arrays ckey_cnt and ckey_cache are allways kept in such a way ! 214: * that the following invariant holds: ! 215: * ckey_cnt > 0 =>'s ckey_cache == 1 ! 216: * meaning as long as a code key is used by at least one process, it's ! 217: * marked as being 'in the cache'. Of course, the following invariant ! 218: * also holds: ! 219: * ckey_cache == 0 =>'s ckey_cnt == 0 ! 220: * which is just the reciprocal of the 1'st invariant. ! 221: * Equivalent invariants hold for the data key arrays. ! 222: */ ! 223: struct keystats ckeystats = { NCKEY - 1 }; ! 224: struct keystats dkeystats = { NDKEY - 1 }; ! 225: ! 226: /* ! 227: * Release a code key. ! 228: */ ! 229: ckeyrelease(key) ! 230: int key; ! 231: { ! 232: register int s; ! 233: ! 234: s = spl8(); ! 235: if (--ckey_cnt[key] < 0) { ! 236: printf("ckeyrelease: key = %d\n", key); ! 237: ckey_cnt[key] = 0; ! 238: } ! 239: if (ckey_cnt[key] == 0) ! 240: ckeystats.ks_dirty++; ! 241: splx(s); ! 242: } ! 243: ! 244: /* ! 245: * Release a data key. ! 246: */ ! 247: dkeyrelease(key) ! 248: int key; ! 249: { ! 250: register int s; ! 251: ! 252: s = spl8(); ! 253: if (--dkey_cnt[key] != 0) { ! 254: printf("dkeyrelease: key = %d\n", key); ! 255: dkey_cnt[key] = 0; ! 256: } ! 257: splx(s); ! 258: dkeystats.ks_dirty++; ! 259: } ! 260: ! 261: /* ! 262: * Invalidate the data cache for a process ! 263: * by exchanging cache keys. ! 264: */ ! 265: dkeyinval(p) ! 266: register struct proc *p; ! 267: { ! 268: int s; ! 269: ! 270: dkeystats.ks_inval++; ! 271: s = spl8(); ! 272: if (--dkey_cnt[p->p_dkey] != 0) ! 273: dkey_cnt[p->p_dkey] = 0; ! 274: if (p == u.u_procp && !noproc) { ! 275: p->p_dkey = getdatakey(); ! 276: mtpr(DCK, p->p_dkey); ! 277: } else ! 278: p->p_dkey = 0; ! 279: splx(s); ! 280: } ! 281: ! 282: /* ! 283: * Get a code key. ! 284: * Strategy: try each of the following in turn ! 285: * until a key is allocated. ! 286: * ! 287: * 1) Find an unreferenced key not yet in the cache. ! 288: * If this fails, a code cache purge will be necessary. ! 289: * 2) Find an unreferenced key. Mark all unreferenced keys ! 290: * as available and purge the cache. ! 291: * 3) Free the keys from all processes not sharing keys. ! 292: * 4) Free the keys from all processes. ! 293: */ ! 294: getcodekey() ! 295: { ! 296: register int i, s, freekey; ! 297: register struct proc *p; ! 298: int desparate = 0; ! 299: static int lastkey = MAXCKEY; ! 300: ! 301: ckeystats.ks_allocs++; ! 302: s = spl8(); ! 303: freekey = 0; ! 304: for (i = lastkey + 1; ; i++) { ! 305: if (i > MAXCKEY) ! 306: i = 1; ! 307: if ((int)ckey_cache[i] == 0) { /* free key, take it */ ! 308: ckey_cache[i] = 1, ckey_cnt[i] = 1; ! 309: splx(s); ! 310: ckeystats.ks_allocfree++; ! 311: ckeystats.ks_avail--; ! 312: lastkey = i; ! 313: return (i); ! 314: } ! 315: if (ckey_cnt[i] == 0) /* save for potential use */ ! 316: freekey = i; ! 317: if (i == lastkey) ! 318: break; ! 319: } ! 320: /* ! 321: * All code keys were marked as being in cache. ! 322: * If a key was in the cache, but not in use, grab it. ! 323: */ ! 324: if (freekey != 0) { ! 325: purge: ! 326: /* ! 327: * If we've run out of free keys, ! 328: * try and free up some other keys to avoid ! 329: * future cache purges. ! 330: */ ! 331: ckey_cnt[freekey] = 1, ckey_cache[freekey] = 1; ! 332: for (i = 1; i <= MAXCKEY; i++) ! 333: if (ckey_cnt[i] == 0) { ! 334: ckey_cache[i] = 0; ! 335: ckeystats.ks_avail++; ! 336: } ! 337: mtpr(PACC, 0); ! 338: splx(s); ! 339: ckeystats.ks_dirty = 0; ! 340: ckeystats.ks_norefs++; ! 341: return (freekey); ! 342: } ! 343: ! 344: /* ! 345: * All keys are marked as in the cache and in use. ! 346: * Release all unshared keys, or, on second pass, ! 347: * release all keys. ! 348: */ ! 349: steal: ! 350: for (p = allproc; p; p = p->p_nxt) ! 351: if (p->p_ckey != 0 && (p->p_flag & SSYS) == 0) { ! 352: i = p->p_ckey; ! 353: if (ckey_cnt[i] == 1 || desparate) { ! 354: p->p_ckey = 0; ! 355: if (--ckey_cnt[i] == 0) { ! 356: freekey = i; ! 357: if (p->p_textp) ! 358: p->p_textp->x_ckey = 0; ! 359: } ! 360: } ! 361: } ! 362: ! 363: if (freekey) { ! 364: ckeystats.ks_taken++; ! 365: goto purge; ! 366: } else { ! 367: desparate++; ! 368: goto steal; ! 369: } ! 370: } ! 371: ! 372: /* ! 373: * Get a data key. ! 374: * ! 375: * General strategy: ! 376: * 1) Try to find a data key that isn't in the cache. Allocate it. ! 377: * 2) If all data keys are in the cache, find one which isn't ! 378: * allocated. Mark all unallocated keys as not in cache, ! 379: * purge the cache, and allocate this one. ! 380: * 3) If all of them are allocated, free all process' keys ! 381: * and let them reclaim then as they run. ! 382: */ ! 383: getdatakey() ! 384: { ! 385: register int i, freekey; ! 386: register struct proc *p; ! 387: int s; ! 388: static int lastkey = MAXDKEY; ! 389: ! 390: dkeystats.ks_allocs++; ! 391: s = spl8(); ! 392: freekey = 0; ! 393: for (i = lastkey + 1; ; i++) { ! 394: if (i > MAXDKEY) ! 395: i = 1; ! 396: if ((int)dkey_cache[i] == 0) { /* free key, take it */ ! 397: dkey_cache[i] = 1, dkey_cnt[i] = 1; ! 398: splx(s); ! 399: dkeystats.ks_allocfree++; ! 400: dkeystats.ks_avail--; ! 401: lastkey = i; ! 402: return (i); ! 403: } ! 404: if (dkey_cnt[i] == 0) ! 405: freekey = i; ! 406: if (i == lastkey) ! 407: break; ! 408: } ! 409: purge: ! 410: if (freekey) { ! 411: /* ! 412: * Try and free up some more keys to avoid ! 413: * future allocations causing a cache purge. ! 414: */ ! 415: dkey_cnt[freekey] = 1, dkey_cache[freekey] = 1; ! 416: for (i = 1; i <= MAXDKEY; i++) ! 417: if (dkey_cnt[i] == 0) { ! 418: dkey_cache[i] = 0; ! 419: dkeystats.ks_avail++; ! 420: } ! 421: mtpr(PADC, 0); ! 422: splx(s); ! 423: dkeystats.ks_norefs++; ! 424: dkeystats.ks_dirty = 0; ! 425: return (freekey); ! 426: } ! 427: ! 428: /* ! 429: * Now, we have to take a key from someone. ! 430: * May as well take them all, so we get them ! 431: * from all of the idle procs. ! 432: */ ! 433: for (p = allproc; p; p = p->p_nxt) ! 434: if (p->p_dkey != 0 && (p->p_flag & SSYS) == 0) { ! 435: freekey = p->p_dkey; ! 436: dkey_cnt[freekey] = 0; ! 437: p->p_dkey = 0; ! 438: } ! 439: dkeystats.ks_taken++; ! 440: goto purge; ! 441: } ! 442: ! 443: /*VARGARGS1*/ ! 444: vtoph(p, v) ! 445: register struct proc *p; ! 446: unsigned v; ! 447: { ! 448: register struct pte *pte; ! 449: register unsigned pg; ! 450: ! 451: pg = btop(v); ! 452: if (pg >= BTOPKERNBASE) ! 453: pte = &Sysmap[pg - BTOPKERNBASE]; ! 454: else ! 455: pte = vtopte(p, pg); ! 456: return ((pte->pg_pfnum << PGSHIFT) + (v & PGOFSET)); ! 457: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.