[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     ! 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