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