|
|
1.1 ! root 1: /* ! 2: * i386/shm0.c ! 3: * ! 4: * Shared memory - memory management interface ! 5: * ! 6: * Revised: Thu May 27 08:09:19 1993 CDT ! 7: */ ! 8: ! 9: /* ! 10: * ---------------------------------------------------------------------- ! 11: * Includes. ! 12: */ ! 13: #include <sys/coherent.h> ! 14: #include <sys/reg.h> ! 15: ! 16: /* ! 17: * ---------------------------------------------------------------------- ! 18: * Definitions. ! 19: * Constants. ! 20: * Macros with argument lists. ! 21: * Typedefs. ! 22: * Enums. ! 23: */ ! 24: #define SHMMAX 0x100000 /* one meg limit on shm seg size */ ! 25: ! 26: /* ! 27: * ---------------------------------------------------------------------- ! 28: * Functions. ! 29: * Import Functions. ! 30: * Export Functions. ! 31: * Local Functions. ! 32: */ ! 33: SR * accShm(); ! 34: void pdCheck(); ! 35: void shmAllDt(); ! 36: SEG * shmAlloc(); ! 37: int shmAtt(); ! 38: int shmAttach(); ! 39: void shmDetach(); ! 40: void shmDetachP(); ! 41: void shmDup(); ! 42: void shmFree(); ! 43: void shmLoad(); ! 44: ! 45: /* ! 46: * ---------------------------------------------------------------------- ! 47: * Global Data. ! 48: * Import Variables. ! 49: * Export Variables. ! 50: * Local Variables. ! 51: */ ! 52: ! 53: /* ! 54: * ---------------------------------------------------------------------- ! 55: * Code. ! 56: */ ! 57: ! 58: /* ! 59: * shmAlloc() ! 60: * ! 61: * Allocate a segment for shared memory that is `bytes_wanted' bytes long. ! 62: * ! 63: * if successful, return allocated SEG * ! 64: * else, return 0 ! 65: * ! 66: * This routine is cloned from smalloc(), from which it differs by ! 67: * (a) locking/unlocking seglink, ! 68: * (b) NOT linking the new segment into segmq, ! 69: * (c) rounding segment size up to a multiple of 4k bytes. ! 70: * ! 71: * The reference counts s_urefc and s_lrefc for a shm segment are 1 ! 72: * at the time of allocation. Each attachment to a new process and ! 73: * each fork of an already attached process will increment these. ! 74: */ ! 75: SEG * ! 76: shmAlloc(bytes_wanted) ! 77: off_t bytes_wanted; ! 78: { ! 79: register SEG *new_seg = 0; ! 80: unsigned int clicks_wanted; ! 81: ! 82: lock(seglink); ! 83: clicks_wanted = btoc(bytes_wanted); ! 84: ! 85: /* Limit size of any shm segment to SHMMAX bytes. */ ! 86: if (bytes_wanted > SHMMAX) ! 87: goto shmAllocDone; ! 88: ! 89: /* ! 90: * Estimate space needed for new segment and its overhead. ! 91: * Fail if not enough free RAM available. ! 92: */ ! 93: if (countsize(clicks_wanted) > allocno()) ! 94: goto shmAllocDone; ! 95: /* ! 96: * Allocate a new SEG struct to keep track of the segment, if possible. ! 97: */ ! 98: if ((new_seg = kalloc(sizeof (SEG))) == NULL) ! 99: goto shmAllocDone; ! 100: ! 101: if ((new_seg->s_vmem = c_alloc(clicks_wanted)) == 0) { ! 102: kfree(new_seg); ! 103: goto shmAllocDone; ! 104: } ! 105: ! 106: new_seg->s_urefc = 1; ! 107: new_seg->s_lrefc = 1; ! 108: new_seg->s_size = ctob(clicks_wanted); ! 109: new_seg->s_flags = SFCORE; ! 110: ! 111: shmAllocDone: ! 112: unlock(seglink); ! 113: return new_seg; ! 114: } ! 115: ! 116: /* ! 117: * shmAtt() ! 118: * ! 119: * Given a pointer "segp" to a SEG which is already allocated, the ! 120: * virtual base address "base" where the segment is to appear, and an ! 121: * index "shm_ix" into p_shmsr[] for a process, set up the ! 122: * SR struct accordingly. ! 123: * ! 124: * Argument "ronflag" is nonzero if segment is to be attached read-only. ! 125: * ! 126: * Return 0 in case of failure, else nonzero. ! 127: */ ! 128: int ! 129: shmAtt(shm_ix, base, segp, ronflag) ! 130: unsigned int shm_ix; ! 131: caddr_t base; ! 132: SEG * segp; ! 133: int ronflag; ! 134: { ! 135: int numBytes = segp->s_size; ! 136: return shmAttach(shm_ix, numBytes, base, segp, ronflag); ! 137: } ! 138: ! 139: /* ! 140: * shmAttach() ! 141: * ! 142: * Given a pointer "segp" to a SEG which is already allocated, the number ! 143: * "numBytes" of bytes in the segment visible in this reference, the ! 144: * virtual base address "base" where the segment is to appear, and an ! 145: * index "shm_ix" into p_shmsr[] for a process, set up the ! 146: * SR struct accordingly. ! 147: * ! 148: * Argument "ronflag" is nonzero if segment is to be attached read-only. ! 149: * ! 150: * Return 0 in case of failure, else nonzero. ! 151: */ ! 152: int ! 153: shmAttach(shm_ix, numBytes, base, segp, ronflag) ! 154: unsigned int shm_ix; ! 155: off_t numBytes; ! 156: caddr_t base; ! 157: SEG * segp; ! 158: int ronflag; ! 159: { ! 160: SR * srp; ! 161: ! 162: /* sanity checks */ ! 163: if (shm_ix >= NSHMSEG || numBytes > segp->s_size) ! 164: return 0; ! 165: ! 166: /* ! 167: * You may find that the base address requested is not ! 168: * supported in the page directory. Since a shm segment ! 169: * may straddle a 4 Mb boundary, there is the possibility ! 170: * of two missing page directory entries. Check for both. ! 171: */ ! 172: pdCheck(base); ! 173: pdCheck(base + segp->s_size - 1); ! 174: ! 175: srp = SELF->p_shmsr + shm_ix; ! 176: srp->sr_base = base; ! 177: srp->sr_flag = (SRFDUMP | SRFDATA); ! 178: if (ronflag) ! 179: srp->sr_flag |= SRFRODT; ! 180: srp->sr_size = numBytes; ! 181: srp->sr_segp = segp; ! 182: ! 183: segp->s_urefc++; ! 184: segp->s_lrefc++; ! 185: ! 186: shmLoad(); ! 187: return 1; ! 188: } ! 189: ! 190: /* ! 191: * shmDetachP() ! 192: * ! 193: * Given an index "shm_ix", into the p_shmsr[] for a process, ! 194: * and a PROC *, detach the indicated shared memory segment. ! 195: */ ! 196: void ! 197: shmDetachP(shm_ix, pp) ! 198: unsigned int shm_ix; ! 199: PROC *pp; ! 200: { ! 201: SR * srp; ! 202: SEG * segp; ! 203: ! 204: if (shm_ix >= NSHMSEG) ! 205: return; ! 206: ! 207: srp = pp->p_shmsr + shm_ix; ! 208: segp = srp->sr_segp; ! 209: ! 210: if (segp) { ! 211: segp->s_urefc--; ! 212: segp->s_lrefc--; ! 213: ! 214: /* We have to set detach time and decrement attachment ! 215: * count. ! 216: */ ! 217: shmSetDs(segp); /* shm1.c */ ! 218: ! 219: /* If it was last attachment and segment was marked to be ! 220: * removed, remove it. ! 221: */ ! 222: if ((segp->s_flags & SRFBERM) ! 223: && segp->s_urefc == 1 && segp->s_lrefc == 1) ! 224: shmFree(segp); ! 225: } ! 226: srp->sr_base = 0; ! 227: srp->sr_flag = 0; ! 228: srp->sr_size = 0; ! 229: srp->sr_segp = 0; ! 230: ! 231: if (pp == SELF) ! 232: shmLoad(); ! 233: } ! 234: ! 235: /* ! 236: * shmDetach() ! 237: * ! 238: * Given an index "shm_ix", into the p_shmsr[] for a process, ! 239: * detach the indicated shared memory segment. ! 240: */ ! 241: void ! 242: shmDetach(shm_ix) ! 243: unsigned int shm_ix; ! 244: { ! 245: shmDetachP(shm_ix, SELF); ! 246: } ! 247: ! 248: /* ! 249: * Scan shared memory for the range of addresses from ! 250: * "base" up to but not including "base" + "count". ! 251: * ! 252: * If any shared memory segment contains the range of addresses, return ! 253: * its SR pointer, otherwise return zero. ! 254: * ! 255: * This routine is used by iomapvp() and sysio(). ! 256: */ ! 257: SR * ! 258: accShm(base, numBytes) ! 259: caddr_t base; ! 260: off_t numBytes; ! 261: { ! 262: SR * srp; ! 263: int i; ! 264: ! 265: for (i = 0; i < NSHMSEG; i++) { ! 266: srp = SELF->p_shmsr + i; ! 267: if (srp->sr_segp && base >= srp->sr_base ! 268: && base + numBytes <= srp->sr_base + srp->sr_size) ! 269: return srp; ! 270: } ! 271: return 0; ! 272: } ! 273: ! 274: /* ! 275: * shmFree() ! 276: * ! 277: * Given a non-null SEG pointer "segp" to a shared memory segment, ! 278: * deallocate the RAM used by that segment. ! 279: * ! 280: * The s_urefc field must be 1 when this routine is called, i.e., there ! 281: * must be no pending attachments to the segment. ! 282: */ ! 283: void ! 284: shmFree(segp) ! 285: SEG * segp; ! 286: { ! 287: if (segp == NULL) { ! 288: printf("shmFree err: NULL argument\n"); ! 289: return; ! 290: } ! 291: ! 292: if (segp->s_urefc != 1 || segp->s_lrefc != 1) { ! 293: printf("shmFree err: segp=%x count=%d\n", segp, segp->s_urefc); ! 294: return; ! 295: } ! 296: ! 297: lock(seglink); ! 298: c_free(segp->s_vmem, btoc(segp->s_size)); ! 299: unlock(seglink); ! 300: ! 301: kfree(segp); ! 302: } ! 303: ! 304: /* ! 305: * Given a PROC pointer "pp", detach ALL shared memory segments from ! 306: * the process. Done during exec and exit. ! 307: */ ! 308: void ! 309: shmAllDt() ! 310: { ! 311: PROC * pp = SELF; ! 312: int i; ! 313: ! 314: for (i = 0; i < NSHMSEG; i++) ! 315: shmDetach(i); ! 316: } ! 317: ! 318: /* ! 319: * Given a PROC pointer "cpp" (e.g. child-of-current-process), ! 320: * duplicate ALL shared memory segments for the process, and update ! 321: * reference counts. Done during fork. ! 322: */ ! 323: void ! 324: shmDup(cpp) ! 325: PROC * cpp; ! 326: { ! 327: int i; ! 328: PROC * pp = SELF; ! 329: SR * srp; ! 330: ! 331: for (i = 0, srp = pp->p_shmsr; i < NSHMSEG; i++, srp++) { ! 332: cpp->p_shmsr[i] = *srp; ! 333: if (srp->sr_segp) { ! 334: srp->sr_segp->s_urefc++; ! 335: srp->sr_segp->s_lrefc++; ! 336: } ! 337: } ! 338: } ! 339: ! 340: /* ! 341: * Load mmu according to shared memory segments. ! 342: */ ! 343: ! 344: void ! 345: shmLoad() ! 346: { ! 347: register int i; ! 348: register SR *srp; ! 349: static SR ushmtab[NSHMSEG]; ! 350: ! 351: /* ! 352: * Unprogram the currently active segments. ! 353: * Reset ushmtab. ! 354: */ ! 355: for (i = 0, srp = ushmtab; i < NSHMSEG; i++, srp++) { ! 356: if (srp->sr_segp) ! 357: unload(srp); ! 358: srp->sr_segp = 0; ! 359: } ! 360: ! 361: /* ! 362: * Load each segment in the SELF->p_shmsr list into the MMU. ! 363: * Remember values in ushmtab. ! 364: */ ! 365: for (i = 0, srp = SELF->p_shmsr; i < NSHMSEG; i++, srp++) { ! 366: if (srp->sr_segp) { ! 367: ushmtab[i] = *srp; ! 368: doload(srp); ! 369: } ! 370: } ! 371: } ! 372: ! 373: /* ! 374: * Given a virtual address "base", check the page directory. If the page ! 375: * directory can't access "base", allocate a 4k page table for the segment and ! 376: * point the page directory at the new page table. ! 377: * ! 378: * This routine is really tricky, so here is a picture of virtual memory: ! 379: * ! 380: * +--------------------+ ! 381: * | U area, etc | ! 382: * |--------------------| 0xFFFF_F000 ! 383: * | Page directory | ! 384: * |--------------------| 0xFFFF_E000 ! 385: * | ... | ! 386: * | Kernel text, data | ! 387: * |--------------------| 0xFFC0_0000 ! 388: * | ----- | <- 4k page table that maps ptable1_v[] (unmapped!) ! 389: * | ... | ! 390: * | ----- | <- 4k page table that maps base (basePTvadd[]) ! 391: * | Page tables | ! 392: * | (ptable1_v[]) | ! 393: * |--------------------| 0xFF80_0000 ! 394: * | ... | ! 395: * | base | ! 396: * | ... | ! 397: * +--------------------+ 0x0000_0000 ! 398: * ! 399: * In comments below, "segment number" is a value in range 0..0x3FF. ! 400: */ ! 401: void ! 402: pdCheck(base) ! 403: { ! 404: int baseSeg; /* Segment number of base */ ! 405: int ptable1_vSeg; /* Segment number of ptable1_v */ ! 406: ! 407: int tabPadd; /* Physical address of new 4k page table */ ! 408: int basePTvadd; /* Virtual address where we want the new page ! 409: table click (in ptable1_v[]). */ ! 410: ! 411: int ptable1_vPTpadd; /* Physical address of page table covering ! 412: segment ptable1_v[]. */ ! 413: int w; /* Temporary virtual click number for ! 414: * ptable1_vPTpadd. */ ! 415: int basePTindex; /* Offset of entry for page table for "base" ! 416: within its page table. */ ! 417: int *unmapped; ! 418: ! 419: baseSeg = btosrd(base); ! 420: ! 421: /* If there is already a page table for "base", nothing to do. */ ! 422: if (ptable0_v[baseSeg] & SEG_PRE) ! 423: return; ! 424: ! 425: /* Get a free click. */ ! 426: DV(baseSeg); ! 427: tabPadd = clickseg(*--sysmem.pfree); ! 428: DV(tabPadd); ! 429: ! 430: /* Point the page directory at the new click. */ ! 431: ptable0_v[baseSeg] = tabPadd | DIR_RW; ! 432: ! 433: /* Now update the page tables so we can access the new click. */ ! 434: ! 435: /* Get physical address for the page table for segment ptable1_v[]. */ ! 436: ptable1_vSeg = btosrd(ptable1_v)&0x3ff; ! 437: DV(ptable1_vSeg); ! 438: ptable1_vPTpadd = ptable0_v[ptable1_vSeg] & ~SEG_BITS; ! 439: DV(ptable1_vPTpadd); ! 440: ! 441: /* Map the click at ptable1_vPTpadd into virtual memory somewhere. */ ! 442: w = workAlloc(); ! 443: DV(w); ! 444: ptable1_v[w] = ptable1_vPTpadd | SEG_SRW; ! 445: mmuupd(); ! 446: ! 447: /* Point page table at new page table click. */ ! 448: basePTvadd = (int)(ptable1_v + btocrd(base)); ! 449: DV(basePTvadd); ! 450: basePTindex = btocrd(basePTvadd) & 0x3FF; ! 451: DV(basePTindex); ! 452: unmapped = (int *)(ctob(w)) + basePTindex; ! 453: DV(unmapped); ! 454: *unmapped = tabPadd | SEG_SRW; ! 455: mmuupd(); ! 456: ! 457: /* Release the temporary click of virtual space. */ ! 458: workFree(w); ! 459: ! 460: /* Now we can write to the new page table. Initialize it empty. */ ! 461: memset(basePTvadd, 0, NBPC); ! 462: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.