|
|
1.1 ! root 1: /* vm_machdep.c 6.1 83/07/29 */ ! 2: ! 3: #include "../machine/pte.h" ! 4: ! 5: #include "../h/param.h" ! 6: #include "../h/systm.h" ! 7: #include "../h/dir.h" ! 8: #include "../h/user.h" ! 9: #include "../h/proc.h" ! 10: #include "../h/cmap.h" ! 11: #include "../h/mount.h" ! 12: #include "../h/vm.h" ! 13: #include "../h/text.h" ! 14: ! 15: #include "../machine/mtpr.h" ! 16: ! 17: /* ! 18: * Set a red zone in the kernel stack after the u. area. ! 19: */ ! 20: setredzone(pte, vaddr) ! 21: register struct pte *pte; ! 22: caddr_t vaddr; ! 23: { ! 24: ! 25: pte += (sizeof (struct user) + NBPG - 1) / NBPG; ! 26: *(int *)pte &= ~PG_PROT; ! 27: *(int *)pte |= PG_URKR; ! 28: if (vaddr) ! 29: mtpr(vaddr + sizeof (struct user) + NBPG - 1, TBIS); ! 30: } ! 31: ! 32: #ifndef mapin ! 33: mapin(pte, v, pfnum, count, prot) ! 34: struct pte *pte; ! 35: u_int v, pfnum; ! 36: int count, prot; ! 37: { ! 38: ! 39: while (count > 0) { ! 40: *(int *)pte++ = pfnum | prot; ! 41: mtpr(ptob(v), TBIS); ! 42: v++; ! 43: pfnum++; ! 44: count--; ! 45: } ! 46: } ! 47: #endif ! 48: ! 49: #ifdef notdef ! 50: /*ARGSUSED*/ ! 51: mapout(pte, size) ! 52: register struct pte *pte; ! 53: int size; ! 54: { ! 55: ! 56: panic("mapout"); ! 57: } ! 58: #endif ! 59: ! 60: /* ! 61: * Check for valid program size ! 62: */ ! 63: chksize(ts, ds, ss) ! 64: register unsigned ts, ds, ss; ! 65: { ! 66: static int maxdmap = 0; ! 67: ! 68: if (ts > MAXTSIZ || ds > MAXDSIZ || ss > MAXSSIZ) { ! 69: u.u_error = ENOMEM; ! 70: return (1); ! 71: } ! 72: /* check for swap map overflow */ ! 73: if (maxdmap == 0) { ! 74: register int i, blk; ! 75: ! 76: blk = dmmin; ! 77: for (i = 0; i < NDMAP; i++) { ! 78: maxdmap += blk; ! 79: if (blk < dmmax) ! 80: blk *= 2; ! 81: } ! 82: } ! 83: if (ctod(ts) > NXDAD * dmtext || ! 84: ctod(ds) > maxdmap || ctod(ss) > maxdmap) { ! 85: u.u_error = ENOMEM; ! 86: return (1); ! 87: } ! 88: /* ! 89: * Make sure the process isn't bigger than our ! 90: * virtual memory limit. ! 91: * ! 92: * THERE SHOULD BE A CONSTANT FOR THIS. ! 93: */ ! 94: if (ts + ds + ss + LOWPAGES + HIGHPAGES > btoc(USRSTACK)) { ! 95: u.u_error = ENOMEM; ! 96: return (1); ! 97: } ! 98: return (0); ! 99: } ! 100: ! 101: /*ARGSUSED*/ ! 102: newptes(pte, v, size) ! 103: register struct pte *pte; ! 104: u_int v; ! 105: register int size; ! 106: { ! 107: register caddr_t a = ptob(v); ! 108: ! 109: #ifdef lint ! 110: pte = pte; ! 111: #endif ! 112: if (size >= 8) { ! 113: mtpr(0, TBIA); ! 114: return; ! 115: } ! 116: while (size > 0) { ! 117: mtpr(a, TBIS); ! 118: a += NBPG; ! 119: size--; ! 120: } ! 121: } ! 122: ! 123: /* ! 124: * Change protection codes of text segment. ! 125: * Have to flush translation buffer since this ! 126: * affect virtual memory mapping of current process. ! 127: */ ! 128: chgprot(addr, tprot) ! 129: caddr_t addr; ! 130: long tprot; ! 131: { ! 132: unsigned v; ! 133: int tp; ! 134: register struct pte *pte; ! 135: register struct cmap *c; ! 136: ! 137: v = clbase(btop(addr)); ! 138: if (!isatsv(u.u_procp, v)) { ! 139: u.u_error = EFAULT; ! 140: return (0); ! 141: } ! 142: tp = vtotp(u.u_procp, v); ! 143: pte = tptopte(u.u_procp, tp); ! 144: if (pte->pg_fod == 0 && pte->pg_pfnum) { ! 145: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 146: if (c->c_blkno && c->c_mdev != MSWAPX) ! 147: munhash(mount[c->c_mdev].m_dev, ! 148: (daddr_t)(u_long)c->c_blkno); ! 149: } ! 150: *(int *)pte &= ~PG_PROT; ! 151: *(int *)pte |= tprot; ! 152: distcl(pte); ! 153: tbiscl(v); ! 154: return (1); ! 155: } ! 156: ! 157: settprot(tprot) ! 158: long tprot; ! 159: { ! 160: register int *ptaddr, i; ! 161: ! 162: ptaddr = (int *)mfpr(P0BR); ! 163: for (i = 0; i < u.u_tsize; i++) { ! 164: ptaddr[i] &= ~PG_PROT; ! 165: ptaddr[i] |= tprot; ! 166: } ! 167: mtpr(0, TBIA); ! 168: } ! 169: ! 170: /* ! 171: * Rest are machine-dependent ! 172: */ ! 173: ! 174: getmemc(addr) ! 175: caddr_t addr; ! 176: { ! 177: register int c; ! 178: struct pte savemap; ! 179: ! 180: savemap = mmap[0]; ! 181: *(int *)mmap = PG_V | PG_KR | btop(addr); ! 182: mtpr(vmmap, TBIS); ! 183: uncache (&vmmap[(int)addr & PGOFSET]); ! 184: c = *(char *)&vmmap[(int)addr & PGOFSET]; ! 185: mmap[0] = savemap; ! 186: mtpr(vmmap, TBIS); ! 187: return (c & 0377); ! 188: } ! 189: ! 190: putmemc(addr, val) ! 191: caddr_t addr; ! 192: { ! 193: struct pte savemap; ! 194: ! 195: savemap = mmap[0]; ! 196: *(int *)mmap = PG_V | PG_KW | btop(addr); ! 197: mtpr(vmmap, TBIS); ! 198: *(char *)&vmmap[(int)addr & PGOFSET] = val; ! 199: ! 200: mtpr (0, PADC); ! 201: mtpr (0, PACC); ! 202: ! 203: mmap[0] = savemap; ! 204: mtpr(vmmap, TBIS); ! 205: } ! 206: ! 207: /* ! 208: * Move pages from one kernel virtual address to another. ! 209: * Both addresses are assumed to reside in the Sysmap, ! 210: * and size must be a multiple of CLSIZE. ! 211: */ ! 212: pagemove(from, to, size) ! 213: register caddr_t from, to; ! 214: int size; ! 215: { ! 216: register struct pte *fpte, *tpte; ! 217: ! 218: if (size % CLBYTES) ! 219: panic("pagemove"); ! 220: fpte = &Sysmap[btop(from - 0xC0000000)]; ! 221: tpte = &Sysmap[btop(to - 0xC0000000)]; ! 222: while (size > 0) { ! 223: *tpte++ = *fpte; ! 224: *(int *)fpte++ = 0; ! 225: mtpr(from, TBIS); ! 226: mtpr(to, TBIS); ! 227: mtpr(to, P1DC); /* purge !! */ ! 228: from += NBPG; ! 229: to += NBPG; ! 230: size -= NBPG; ! 231: } ! 232: } ! 233: ! 234: /* ! 235: * Some code and data key management routines. ! 236: * The arrays ckey_cnt and ckey_cache are allways kept in such a way ! 237: * that the following invariant holds: ! 238: * (ckey_cnt > 0) ==> (ckey_cache == 1) ! 239: * meaning as long as a code key is used by at least one process, it's ! 240: * marked as being 'in the cache'. Of course, the following invariant ! 241: * also holds: ! 242: * (ckey_cache==0) ==> (ckey_cnt==0) ! 243: * which is just the reciprocal of the 1'st invariant. ! 244: * Equivalent invariants hold for the data key arrays. ! 245: */ ! 246: ! 247: ! 248: int dbg_gck, ! 249: dbg_gck1, ! 250: dbg_gck2, ! 251: dbg_gck3, ! 252: dbg_gck4, ! 253: dbg_gdk, ! 254: dbg_gdk1, ! 255: dbg_gdk2, ! 256: dbg_gdk3; ! 257: ! 258: /* ! 259: * ckeyrelease -- release a code key. ! 260: */ ! 261: ckeyrelease (key) ! 262: int key; ! 263: { ! 264: register int ipl; ! 265: ! 266: ipl = spl8(); ! 267: if (--ckey_cnt[key] < 0) { ! 268: printf ("ckeyrelease: key = %d\n", key); ! 269: ckey_cnt[key] = 0; ! 270: } ! 271: splx (ipl); ! 272: } ! 273: ! 274: ! 275: /* ! 276: * dkeyrelease -- release a data key. ! 277: */ ! 278: dkeyrelease (key) ! 279: int key; ! 280: { ! 281: register int ipl; ! 282: ! 283: ipl = spl8(); ! 284: if (--dkey_cnt[key] != 0) { ! 285: printf ("dkeyrelease: key = %d\n", key); ! 286: dkey_cnt[key] = 0; ! 287: } ! 288: splx (ipl); ! 289: } ! 290: ! 291: ! 292: /* ! 293: * getcodekey -- get a code key. ! 294: */ ! 295: getcodekey() ! 296: { ! 297: register int i, ! 298: ipl, ! 299: allocated, /* number of non-zero ckey_cnt's */ ! 300: shared_key, ! 301: return_key; ! 302: register struct proc *p; ! 303: ! 304: dbg_gck++; ! 305: ! 306: ipl = spl8(); ! 307: allocated = 0; ! 308: ! 309: for (i = 1; i <= MAXCKEY; i++) { ! 310: if ((int) ckey_cache[i] == 0) { /* Bingo */ ! 311: ckey_cache[i] = 1; ! 312: ckey_cnt[i] = 1; ! 313: splx (ipl); ! 314: dbg_gck1++; ! 315: return (i); ! 316: } ! 317: ! 318: if (ckey_cnt[i] != 0) ! 319: allocated++; ! 320: if (ckey_cnt[i] > 1 && i != MAXCKEY) ! 321: shared_key = i; ! 322: } ! 323: ! 324: /* ! 325: * If we are here, all code keys were marked as being in cache. ! 326: * Moreover, we are assured that 'shared_key' has a meaningful value, ! 327: * since we know that the 'init' process and the 'shell' are around ! 328: * and they have shared text! ! 329: * ! 330: * Two cases: some of them are free for re-allocation, or all of ! 331: * them are currently allocated. In this (second) case, a more ! 332: * drastic procedure will follow - i.e. we strip some processes of ! 333: * their keys and let them get new ones whenever they need it. ! 334: */ ! 335: if (allocated < MAXCKEY) { ! 336: /* ! 337: * This is the easy case. ! 338: */ ! 339: for (i = 1; i <= MAXCKEY; i++) { ! 340: if (ckey_cnt[i] == 0) { ! 341: ckey_cache[i] = 0; ! 342: return_key = i; ! 343: } ! 344: } ! 345: ! 346: ckey_cnt[return_key] = 1; ! 347: ckey_cache[return_key] = 1; ! 348: mtpr (0, PACC); ! 349: splx (ipl); ! 350: dbg_gck2++; ! 351: return (return_key); ! 352: } ! 353: ! 354: /* ! 355: * Now we have to get nasty. ! 356: * Strip some of them of the code key. First time, ! 357: * 1) Try hard not to do that to kernel processes !! ! 358: * 2) Try hard NOT to strip shared text processes of ! 359: * their (shared) key, because then they'll run ! 360: * with different keys from now on, i.e. less efficient ! 361: * cache utilization. ! 362: */ ! 363: for (p = proc; p < procNPROC; p++) { ! 364: /* ! 365: * Look for a meaningful key but not ! 366: * used and not shared text. ! 367: */ ! 368: if (p->p_ckey && p->p_ckey!=MAXCKEY && ckey_cnt[p->p_ckey]<2) { ! 369: i = p->p_ckey; ! 370: p->p_ckey = 0; ! 371: ckey_cnt[i] = 1; ! 372: ckey_cache[i] = 1; ! 373: mtpr (0, PACC); ! 374: splx (ipl); ! 375: dbg_gck3++; ! 376: return (i); ! 377: } ! 378: } ! 379: ! 380: /* ! 381: * Second time around! ! 382: * Highly unlikely situation. It means that all keys are ! 383: * allocated AND shared (i.e. we have at least 510 active ! 384: * processes). ! 385: * Strip some of them. We pick some key (known to be shared ! 386: * by several processes) and strip the poor process group. ! 387: * At least 2 processes will loose but we gain one key to be reused. ! 388: * The way 'shared_key' was produced (above) virtually assures ! 389: * us that this key isn't the 'init' group key (1) nor the ! 390: * 'shell' group key (2 or 3). It's probably something like 254. ! 391: * Could be more straightforward to strip all processes, but it's ! 392: * better to invest in one more loop here and keep the cache ! 393: * utilization to a maximum. ! 394: */ ! 395: for (p = proc; p < procNPROC; p++) { ! 396: if (p->p_ckey == shared_key) { ! 397: p->p_ckey = 0; ! 398: ckey_cnt[shared_key]--; ! 399: } ! 400: } ! 401: ! 402: if (ckey_cnt[shared_key] != 0) ! 403: printf("getcodekey: key = %d cnt = %d\n", ! 404: shared_key, ckey_cnt[shared_key]); ! 405: ! 406: ckey_cnt[shared_key] = 1; ! 407: ckey_cache[shared_key] = 1; ! 408: mtpr (0, PACC); ! 409: splx (ipl); ! 410: dbg_gck4++; ! 411: return (shared_key); ! 412: } ! 413: ! 414: ! 415: /* ! 416: * getdatakey -- get a data key. ! 417: * ! 418: * General strategy: ! 419: * 1) Try to find a data key that isn't in the cache. Allocate it. ! 420: * 2) If all data keys are in the cache, find one which isn't ! 421: * allocated. Clear all status and allocate this one. ! 422: * 3) If all of them are allocated, pick some process, strip him ! 423: * of the data key and allocate it. We (cold-bloodedly) pick ! 424: * one process to be the poor looser because that's the ! 425: * easiest way to do it and because this extreme situation ! 426: * ( >255 active processes ) is expected to be temporary, ! 427: * after which 1) or 2) above should be the usual case. ! 428: * The poor looser is the first process which has a data key. ! 429: * However, we try to spare known kernel processes and daemons ! 430: * (fired at bootstrap time), by searching from proc[LOOSER] and on. ! 431: */ ! 432: getdatakey() ! 433: { ! 434: register int i, ! 435: ipl, ! 436: allocated, /* number of non-zero dkey_cnt's */ ! 437: return_key; ! 438: register struct proc *p; ! 439: ! 440: #define LOOSER 20 ! 441: ! 442: dbg_gdk++; ! 443: ! 444: ipl = spl8(); ! 445: allocated = 0; ! 446: for (i = 1; i <= MAXDKEY; i++) { ! 447: if ((int) dkey_cache[i] == 0) { ! 448: /* ! 449: * Case 1. The best case. ! 450: */ ! 451: dkey_cache[i] = 1; ! 452: dkey_cnt[i] = 1; ! 453: splx (ipl); ! 454: dbg_gdk1++; ! 455: return (i); ! 456: } ! 457: if (dkey_cnt[i] > 0) ! 458: allocated++; ! 459: } ! 460: ! 461: if (allocated < MAXDKEY) { ! 462: /* ! 463: * Case 2. This is the easy case. ! 464: */ ! 465: for (i = 1; i <= MAXDKEY; i++) { ! 466: if (dkey_cnt[i] == 0) { ! 467: dkey_cache[i] = 0; ! 468: return_key = i; ! 469: } ! 470: } ! 471: ! 472: dkey_cnt[return_key] = 1; ! 473: dkey_cache[return_key] = 1; ! 474: mtpr (0, PADC); ! 475: splx (ipl); ! 476: dbg_gdk2++; ! 477: return (return_key); ! 478: } ! 479: ! 480: /* ! 481: * Now, we have to take a code from someone. ! 482: */ ! 483: for (p = &proc[LOOSER]; p < procNPROC; p++) { ! 484: if (p->p_dkey != 0) { ! 485: i = p->p_dkey; ! 486: p->p_dkey = 0; ! 487: dkey_cnt[i] = 1; ! 488: dkey_cache[i] = 1; ! 489: mtpr (0, PADC); ! 490: splx (ipl); ! 491: dbg_gdk3++; ! 492: return (i); ! 493: } ! 494: } ! 495: ! 496: panic ("getdatakey"); ! 497: } ! 498: ! 499: ! 500: /* General (includes system) virtual address to physical */ ! 501: vtoph(p, v) ! 502: register struct proc *p; ! 503: register unsigned v; ! 504: { ! 505: register struct pte *thispte; ! 506: ! 507: thispte = vtopte (p, btop(v)); ! 508: return ( (thispte->pg_pfnum << PGSHIFT) + (v & PGOFSET)); ! 509: } ! 510:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.