Annotation of coherent/b/kernel/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: #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: }

unix.superglobalmegacorp.com

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