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