Annotation of coherent/b/STREAMS/i386/shm0.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.