Annotation of coherent/b/STREAMS/i386/shm0.c, revision 1.1.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.