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