[BACK]Return to vm_machdep.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc / sparc

Annotation of sys/arch/sparc/sparc/vm_machdep.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: vm_machdep.c,v 1.49 2007/06/20 17:29:36 miod Exp $    */
                      2: /*     $NetBSD: vm_machdep.c,v 1.30 1997/03/10 23:55:40 pk Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (c) 1996
                      6:  *     The President and Fellows of Harvard College. All rights reserved.
                      7:  * Copyright (c) 1992, 1993
                      8:  *     The Regents of the University of California.  All rights reserved.
                      9:  *
                     10:  * This software was developed by the Computer Systems Engineering group
                     11:  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
                     12:  * contributed to Berkeley.
                     13:  *
                     14:  * All advertising materials mentioning features or use of this software
                     15:  * must display the following acknowledgement:
                     16:  *     This product includes software developed by the University of
                     17:  *     California, Lawrence Berkeley Laboratory.
                     18:  *     This product includes software developed by Harvard University.
                     19:  *
                     20:  * Redistribution and use in source and binary forms, with or without
                     21:  * modification, are permitted provided that the following conditions
                     22:  * are met:
                     23:  * 1. Redistributions of source code must retain the above copyright
                     24:  *    notice, this list of conditions and the following disclaimer.
                     25:  * 2. Redistributions in binary form must reproduce the above copyright
                     26:  *    notice, this list of conditions and the following disclaimer in the
                     27:  *    documentation and/or other materials provided with the distribution.
                     28:  * 3. All advertising materials mentioning features or use of this software
                     29:  *    must display the following acknowledgement:
                     30:  *     This product includes software developed by Harvard University.
                     31:  *     This product includes software developed by the University of
                     32:  *     California, Berkeley and its contributors.
                     33:  * 4. Neither the name of the University nor the names of its contributors
                     34:  *    may be used to endorse or promote products derived from this software
                     35:  *    without specific prior written permission.
                     36:  *
                     37:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     38:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     39:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     40:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     41:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     42:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     43:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     44:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     45:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     46:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     47:  * SUCH DAMAGE.
                     48:  *
                     49:  *     @(#)vm_machdep.c        8.2 (Berkeley) 9/23/93
                     50:  */
                     51:
                     52: #include <sys/param.h>
                     53: #include <sys/systm.h>
                     54: #include <sys/proc.h>
                     55: #include <sys/signalvar.h>
                     56: #include <sys/user.h>
                     57: #include <sys/core.h>
                     58: #include <sys/malloc.h>
                     59: #include <sys/buf.h>
                     60: #include <sys/exec.h>
                     61: #include <sys/vnode.h>
                     62: #include <sys/extent.h>
                     63:
                     64: #include <uvm/uvm_extern.h>
                     65:
                     66: #include <machine/cpu.h>
                     67: #include <machine/frame.h>
                     68: #include <machine/trap.h>
                     69:
                     70: #include <sparc/sparc/cpuvar.h>
                     71:
                     72: /*
                     73:  * Wrapper for dvma_mapin() in kernel space,
                     74:  * so drivers need not include VM goo to get at kernel_map.
                     75:  */
                     76: caddr_t
                     77: kdvma_mapin(va, len, canwait)
                     78:        caddr_t va;
                     79:        int     len, canwait;
                     80: {
                     81:        return ((caddr_t)dvma_mapin(kernel_map, (vaddr_t)va, len, canwait));
                     82: }
                     83:
                     84: #if defined(SUN4M)
                     85: extern int has_iocache;
                     86: #endif
                     87:
                     88: caddr_t
                     89: dvma_malloc_space(len, kaddr, flags, space)
                     90:        size_t  len;
                     91:        void    *kaddr;
                     92:        int     flags;
                     93: {
                     94:        vaddr_t kva;
                     95:        vaddr_t dva;
                     96:
                     97:        len = round_page(len);
                     98:        kva = (vaddr_t)malloc(len, M_DEVBUF, flags);
                     99:        if (kva == NULL)
                    100:                return (NULL);
                    101:
                    102: #if defined(SUN4M)
                    103:        if (!has_iocache)
                    104: #endif
                    105:                kvm_uncache((caddr_t)kva, atop(len));
                    106:
                    107:        *(vaddr_t *)kaddr = kva;
                    108:        dva = dvma_mapin_space(kernel_map, kva, len, (flags & M_NOWAIT) ? 0 : 1, space);
                    109:        if (dva == NULL) {
                    110:                free((void *)kva, M_DEVBUF);
                    111:                return (NULL);
                    112:        }
                    113:        return (caddr_t)dva;
                    114: }
                    115:
                    116: void
                    117: dvma_free(dva, len, kaddr)
                    118:        caddr_t dva;
                    119:        size_t  len;
                    120:        void    *kaddr;
                    121: {
                    122:        vaddr_t kva = *(vaddr_t *)kaddr;
                    123:
                    124:        len = round_page(len);
                    125:
                    126:        dvma_mapout((vaddr_t)dva, kva, len);
                    127:        /*
                    128:         * Even if we're freeing memory here, we can't be sure that it will
                    129:         * be unmapped, so we must recache the memory range to avoid impact
                    130:         * on other kernel subsystems.
                    131:         */
                    132: #if defined(SUN4M)
                    133:        if (!has_iocache)
                    134: #endif
                    135:                kvm_recache(kaddr, atop(len));
                    136:        free((void *)kva, M_DEVBUF);
                    137: }
                    138:
                    139: u_long dvma_cachealign = 0;
                    140:
                    141: /*
                    142:  * Map a range [va, va+len] of wired virtual addresses in the given map
                    143:  * to a kernel address in DVMA space.
                    144:  */
                    145: vaddr_t
                    146: dvma_mapin_space(map, va, len, canwait, space)
                    147:        struct vm_map   *map;
                    148:        vaddr_t va;
                    149:        int             len, canwait, space;
                    150: {
                    151:        vaddr_t kva, tva;
                    152:        int npf, s;
                    153:        paddr_t pa;
                    154:        vaddr_t off;
                    155:        vaddr_t ova;
                    156:        int olen;
                    157:        int error;
                    158:
                    159:        if (dvma_cachealign == 0)
                    160:                dvma_cachealign = PAGE_SIZE;
                    161:
                    162:        ova = va;
                    163:        olen = len;
                    164:
                    165:        off = va & PAGE_MASK;
                    166:        va &= ~PAGE_MASK;
                    167:        len = round_page(len + off);
                    168:        npf = btoc(len);
                    169:
                    170:        s = splhigh();
                    171:        if (space & M_SPACE_D24)
                    172:                error = extent_alloc_subregion(dvmamap_extent,
                    173:                    DVMA_D24_BASE, DVMA_D24_END, len, dvma_cachealign,
                    174:                    va & (dvma_cachealign - 1), 0,
                    175:                    canwait ? EX_WAITSPACE : EX_NOWAIT, &tva);
                    176:        else
                    177:                error = extent_alloc(dvmamap_extent, len, dvma_cachealign,
                    178:                    va & (dvma_cachealign - 1), 0,
                    179:                    canwait ? EX_WAITSPACE : EX_NOWAIT, &tva);
                    180:        splx(s);
                    181:        if (error)
                    182:                return NULL;
                    183:        kva = tva;
                    184:
                    185:        while (npf--) {
                    186:                if (pmap_extract(vm_map_pmap(map), va, &pa) == FALSE)
                    187:                        panic("dvma_mapin: null page frame");
                    188:                pa = trunc_page(pa);
                    189:
                    190: #if defined(SUN4M)
                    191:                if (CPU_ISSUN4M) {
                    192:                        iommu_enter(tva, pa);
                    193:                } else
                    194: #endif
                    195:                {
                    196:                        /*
                    197:                         * pmap_enter distributes this mapping to all
                    198:                         * contexts... maybe we should avoid this extra work
                    199:                         */
                    200: #ifdef notyet
                    201: #if defined(SUN4)
                    202:                        if (have_iocache)
                    203:                                pa |= PG_IOC;
                    204: #endif
                    205: #endif
                    206:                        /* XXX - this should probably be pmap_kenter */
                    207:                        pmap_enter(pmap_kernel(), tva, pa | PMAP_NC,
                    208:                                   VM_PROT_READ | VM_PROT_WRITE, PMAP_WIRED);
                    209:                }
                    210:
                    211:                tva += PAGE_SIZE;
                    212:                va += PAGE_SIZE;
                    213:        }
                    214:        pmap_update(pmap_kernel());
                    215:
                    216:        /*
                    217:         * XXX Only have to do this on write.
                    218:         */
                    219:        if (CACHEINFO.c_vactype == VAC_WRITEBACK)       /* XXX */
                    220:                cpuinfo.cache_flush((caddr_t)ova, olen);        /* XXX */
                    221:
                    222:        return kva + off;
                    223: }
                    224:
                    225: /*
                    226:  * Remove double map of `va' in DVMA space at `kva'.
                    227:  */
                    228: void
                    229: dvma_mapout(kva, va, len)
                    230:        vaddr_t kva, va;
                    231:        int             len;
                    232: {
                    233:        int s, off;
                    234:        int error;
                    235:        int klen;
                    236:
                    237:        off = (int)kva & PGOFSET;
                    238:        kva -= off;
                    239:        klen = round_page(len + off);
                    240:
                    241: #if defined(SUN4M)
                    242:        if (CPU_ISSUN4M)
                    243:                iommu_remove(kva, klen);
                    244:        else
                    245: #endif
                    246:        {
                    247:                pmap_remove(pmap_kernel(), kva, kva + klen);
                    248:                pmap_update(pmap_kernel());
                    249:        }
                    250:
                    251:        s = splhigh();
                    252:        error = extent_free(dvmamap_extent, kva, klen, EX_NOWAIT);
                    253:        if (error)
                    254:                printf("dvma_mapout: extent_free failed\n");
                    255:        splx(s);
                    256:
                    257:        if (CACHEINFO.c_vactype != VAC_NONE)
                    258:                cpuinfo.cache_flush((caddr_t)va, len);
                    259: }
                    260:
                    261: /*
                    262:  * Map an IO request into kernel virtual address space.
                    263:  */
                    264: void
                    265: vmapbuf(struct buf *bp, vsize_t sz)
                    266: {
                    267:        vaddr_t uva, kva;
                    268:        vsize_t size, off;
                    269:        struct pmap *pmap;
                    270:        paddr_t pa;
                    271:
                    272: #ifdef DIAGNOSTIC
                    273:        if ((bp->b_flags & B_PHYS) == 0)
                    274:                panic("vmapbuf");
                    275: #endif
                    276:        pmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);
                    277:
                    278:        bp->b_saveaddr = bp->b_data;
                    279:        uva = trunc_page((vaddr_t)bp->b_data);
                    280:        off = (vaddr_t)bp->b_data - uva;
                    281:        size = round_page(off + sz);
                    282:        /*
                    283:         * Note that this is an expanded version of:
                    284:         *   kva = uvm_km_valloc_wait(kernel_map, size);
                    285:         * We do it on our own here to be able to specify an offset to uvm_map
                    286:         * so that we can get all benefits of PMAP_PREFER.
                    287:         */
                    288:        kva = uvm_km_valloc_prefer_wait(kernel_map, size, uva);
                    289:        bp->b_data = (caddr_t)(kva + off);
                    290:
                    291:        while (size > 0) {
                    292:                if (pmap_extract(pmap, uva, &pa) == FALSE)
                    293:                        panic("vmapbuf: null page frame");
                    294:
                    295:                /*
                    296:                 * Don't enter uncached if cache is mandatory.
                    297:                 *
                    298:                 * XXX - there are probably other cases where we don't need
                    299:                 *       to uncache, but for now we're conservative.
                    300:                 */
                    301:                if (!(cpuinfo.flags & CPUFLG_CACHE_MANDATORY))
                    302:                        pa |= PMAP_NC;
                    303:
                    304:                pmap_enter(pmap_kernel(), kva, pa,
                    305:                           VM_PROT_READ | VM_PROT_WRITE, PMAP_WIRED);
                    306:
                    307:                uva += PAGE_SIZE;
                    308:                kva += PAGE_SIZE;
                    309:                size -= PAGE_SIZE;
                    310:        }
                    311:        pmap_update(pmap_kernel());
                    312: }
                    313:
                    314: /*
                    315:  * Free the io map addresses associated with this IO operation.
                    316:  */
                    317: void
                    318: vunmapbuf(bp, sz)
                    319:        register struct buf *bp;
                    320:        vsize_t sz;
                    321: {
                    322:        register vaddr_t kva;
                    323:        register vsize_t size, off;
                    324:
                    325:        if ((bp->b_flags & B_PHYS) == 0)
                    326:                panic("vunmapbuf");
                    327:
                    328:        kva = trunc_page((vaddr_t)bp->b_data);
                    329:        off = (vaddr_t)bp->b_data - kva;
                    330:        size = round_page(sz + off);
                    331:
                    332:        pmap_remove(pmap_kernel(), kva, kva + size);
                    333:        pmap_update(pmap_kernel());
                    334:        uvm_km_free_wakeup(kernel_map, kva, size);
                    335:        bp->b_data = bp->b_saveaddr;
                    336:        bp->b_saveaddr = NULL;
                    337:        if (CACHEINFO.c_vactype != VAC_NONE)
                    338:                cpuinfo.cache_flush(bp->b_data, bp->b_bcount - bp->b_resid);
                    339: }
                    340:
                    341:
                    342: /*
                    343:  * The offset of the topmost frame in the kernel stack.
                    344:  */
                    345: #define        TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-sizeof(struct frame))
                    346:
                    347: /*
                    348:  * Finish a fork operation, with process p2 nearly set up.
                    349:  * Copy and update the pcb, making the child ready to run, and marking
                    350:  * it so that it can return differently than the parent.
                    351:  *
                    352:  * This function relies on the fact that the pcb is
                    353:  * the first element in struct user.
                    354:  */
                    355: void
                    356: cpu_fork(p1, p2, stack, stacksize, func, arg)
                    357:        struct proc *p1, *p2;
                    358:        void *stack;
                    359:        size_t stacksize;
                    360:        void (*func)(void *);
                    361:        void *arg;
                    362: {
                    363:        struct pcb *opcb = &p1->p_addr->u_pcb;
                    364:        struct pcb *npcb = &p2->p_addr->u_pcb;
                    365:        struct trapframe *tf2;
                    366:        struct rwindow *rp;
                    367:
                    368:        /*
                    369:         * Save all user registers to p1's stack or, in the case of
                    370:         * user registers and invalid stack pointers, to opcb.
                    371:         * We then copy the whole pcb to p2; when switch() selects p2
                    372:         * to run, it will run at the `proc_trampoline' stub, rather
                    373:         * than returning at the copying code below.
                    374:         *
                    375:         * If process p1 has an FPU state, we must copy it.  If it is
                    376:         * the FPU user, we must save the FPU state first.
                    377:         */
                    378:
                    379:        if (p1 == curproc) {
                    380:                write_user_windows();
                    381:                opcb->pcb_psr = getpsr();
                    382:        }
                    383: #ifdef DIAGNOSTIC
                    384:        else if (p1 != &proc0)
                    385:                panic("cpu_fork: curproc");
                    386: #endif
                    387:
                    388:        bcopy((caddr_t)opcb, (caddr_t)npcb, sizeof(struct pcb));
                    389:        if (p1->p_md.md_fpstate) {
                    390:                if (p1 == cpuinfo.fpproc)
                    391:                        savefpstate(p1->p_md.md_fpstate);
                    392:                p2->p_md.md_fpstate = malloc(sizeof(struct fpstate),
                    393:                    M_SUBPROC, M_WAITOK);
                    394:                bcopy(p1->p_md.md_fpstate, p2->p_md.md_fpstate,
                    395:                    sizeof(struct fpstate));
                    396:        } else
                    397:                p2->p_md.md_fpstate = NULL;
                    398:
                    399:        /*
                    400:         * Setup (kernel) stack frame that will by-pass the child
                    401:         * out of the kernel. (The trap frame invariably resides at
                    402:         * the tippity-top of the u. area.)
                    403:         */
                    404:        tf2 = p2->p_md.md_tf = (struct trapframe *)
                    405:                        ((int)npcb + USPACE - sizeof(*tf2));
                    406:
                    407:        /* Copy parent's trapframe */
                    408:        *tf2 = *(struct trapframe *)((int)opcb + USPACE - sizeof(*tf2));
                    409:
                    410:        /*
                    411:         * If specified, give the child a different stack.
                    412:         */
                    413:        if (stack != NULL)
                    414:                tf2->tf_out[6] = (u_int)stack + stacksize;
                    415:
                    416:        /* Duplicate efforts of syscall(), but slightly differently */
                    417:        if (tf2->tf_global[1] & SYSCALL_G2RFLAG) {
                    418:                /* jmp %g2 (or %g7, deprecated) on success */
                    419:                tf2->tf_npc = tf2->tf_global[2];
                    420:        } else {
                    421:                /*
                    422:                 * old system call convention: clear C on success
                    423:                 * note: proc_trampoline() sets a fresh psr when
                    424:                 * returning to user mode.
                    425:                 */
                    426:                /*tf2->tf_psr &= ~PSR_C;   -* success */
                    427:        }
                    428:
                    429:        /* Set return values in child mode */
                    430:        tf2->tf_out[0] = 0;
                    431:        tf2->tf_out[1] = 1;
                    432:
                    433:        /* Skip trap instruction. */
                    434:        tf2->tf_pc = tf2->tf_npc;
                    435:        tf2->tf_npc += 4;
                    436:
                    437:        /* Construct kernel frame to return to in cpu_switch() */
                    438:        rp = (struct rwindow *)((u_int)npcb + TOPFRAMEOFF);
                    439:        rp->rw_local[0] = (int)func;            /* Function to call */
                    440:        rp->rw_local[1] = (int)arg;             /* and its argument */
                    441:
                    442:        npcb->pcb_pc = (int)proc_trampoline - 8;
                    443:        npcb->pcb_sp = (int)rp;
                    444:        npcb->pcb_psr &= ~PSR_CWP;      /* Run in window #0 */
                    445:        npcb->pcb_wim = 1;              /* Fence at window #1 */
                    446:
                    447: }
                    448:
                    449: /*
                    450:  * cpu_exit is called as the last action during exit.
                    451:  *
                    452:  * We clean up a little and then call switchexit() with the old proc
                    453:  * as an argument.  switchexit() switches to the idle context, schedules
                    454:  * the old vmspace and stack to be freed, then selects a new process to
                    455:  * run.
                    456:  */
                    457: void
                    458: cpu_exit(p)
                    459:        struct proc *p;
                    460: {
                    461:        register struct fpstate *fs;
                    462:
                    463:        if ((fs = p->p_md.md_fpstate) != NULL) {
                    464:                if (p == cpuinfo.fpproc) {
                    465:                        savefpstate(fs);
                    466:                        cpuinfo.fpproc = NULL;
                    467:                }
                    468:                free((void *)fs, M_SUBPROC);
                    469:        }
                    470:
                    471:        switchexit(p);
                    472:        /* NOTREACHED */
                    473: }
                    474:
                    475: /*
                    476:  * cpu_coredump is called to write a core dump header.
                    477:  * (should this be defined elsewhere?  machdep.c?)
                    478:  */
                    479: int
                    480: cpu_coredump(p, vp, cred, chdr)
                    481:        struct proc *p;
                    482:        struct vnode *vp;
                    483:        struct ucred *cred;
                    484:        struct core *chdr;
                    485: {
                    486:        int error;
                    487:        struct md_coredump md_core;
                    488:        struct coreseg cseg;
                    489:
                    490:        CORE_SETMAGIC(*chdr, COREMAGIC, MID_SPARC, 0);
                    491:        chdr->c_hdrsize = ALIGN(sizeof(*chdr));
                    492:        chdr->c_seghdrsize = ALIGN(sizeof(cseg));
                    493:        chdr->c_cpusize = sizeof(md_core);
                    494:
                    495:        md_core.md_tf = *p->p_md.md_tf;
                    496:        md_core.md_wcookie = p->p_addr->u_pcb.pcb_wcookie;
                    497:        if (p->p_md.md_fpstate) {
                    498:                if (p == cpuinfo.fpproc)
                    499:                        savefpstate(p->p_md.md_fpstate);
                    500:                md_core.md_fpstate = *p->p_md.md_fpstate;
                    501:        } else
                    502:                bzero((caddr_t)&md_core.md_fpstate, sizeof(struct fpstate));
                    503:
                    504:        CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_SPARC, CORE_CPU);
                    505:        cseg.c_addr = 0;
                    506:        cseg.c_size = chdr->c_cpusize;
                    507:        error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize,
                    508:            (off_t)chdr->c_hdrsize, UIO_SYSSPACE,
                    509:            IO_NODELOCKED|IO_UNIT, cred, NULL, p);
                    510:        if (error)
                    511:                return error;
                    512:
                    513:        error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&md_core, sizeof(md_core),
                    514:            (off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE,
                    515:            IO_NODELOCKED|IO_UNIT, cred, NULL, p);
                    516:        if (!error)
                    517:                chdr->c_nseg++;
                    518:
                    519:        return error;
                    520: }

CVSweb