paddr_t sun68k_bus_mmap(bus_space_tag_t t, bus_type_t iospace, bus_addr_t paddr, off_t offset, int prot, int flags) { paddr_t npaddr; npaddr = m68k_trunc_page(paddr + offset); return (npaddr | (paddr_t)iospace | PMAP_NC); }
void bus_tmapout(void *vp) { vaddr_t pgva; pgva = m68k_trunc_page(vp); if (pgva != tmp_vpages[1]) return; set_pte(pgva, PG_INVAL); --tmp_vpages_inuse; }
void bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) { vaddr_t kva; vsize_t offset; if (t->bustype == HP300_BUS_SPACE_INTIO) { /* * Intio space is direct-mapped in pmap_bootstrap(); nothing * to do */ return; } if (t->bustype != HP300_BUS_SPACE_DIO && t->bustype != HP300_BUS_SPACE_SGC) panic("%s: bad space tag", __func__); kva = m68k_trunc_page(bsh); offset = m68k_page_offset(bsh); size = m68k_round_page(offset + size); #ifdef DIAGNOSTIC if (bsh < (vaddr_t)extiobase || bsh >= ((vaddr_t)extiobase + ptoa(EIOMAPSIZE))) panic("%s: bad bus space handle", __func__); #endif /* * Unmap the range. */ physunaccess((void *)kva, size); /* * Free it from the extio extent map. */ if (extent_free(extio_ex, kva, size, EX_NOWAIT | (extio_ex_malloc_safe ? EX_MALLOCOK : 0))) printf("%s: kva 0x%lx size 0x%lx: " "can't free region\n", __func__, (u_long)bsh, size); }
/* * Unmap a previously-mapped user I/O request. */ void vunmapbuf(struct buf *bp, vsize_t len) { vaddr_t kva; vsize_t off; if ((bp->b_flags & B_PHYS) == 0) panic("vunmapbuf"); kva = m68k_trunc_page(bp->b_data); off = (vaddr_t)bp->b_data - kva; len = m68k_round_page(off + len); #ifdef M68K_VAC pmap_remove(vm_map_pmap(phys_map), kva, kva + len); #else pmap_kremove(kva, len); #endif pmap_update(pmap_kernel()); uvm_km_free(phys_map, kva, len, UVM_KMF_VAONLY); bp->b_data = bp->b_saveaddr; bp->b_saveaddr = 0; }
/* * Map a user I/O request into kernel virtual address space. * Note: the pages are already locked by uvm_vslock(), so we * do not need to pass an access_type to pmap_enter(). */ int vmapbuf(struct buf *bp, vsize_t len) { struct pmap *upmap, *kpmap __unused; vaddr_t uva; /* User VA (map from) */ vaddr_t kva; /* Kernel VA (new to) */ paddr_t pa; /* physical address */ vsize_t off; if ((bp->b_flags & B_PHYS) == 0) panic("vmapbuf"); uva = m68k_trunc_page(bp->b_saveaddr = bp->b_data); off = (vaddr_t)bp->b_data - uva; len = m68k_round_page(off + len); kva = uvm_km_alloc(phys_map, len, 0, UVM_KMF_VAONLY | UVM_KMF_WAITVA); bp->b_data = (void *)(kva + off); upmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map); kpmap = vm_map_pmap(phys_map); do { if (pmap_extract(upmap, uva, &pa) == false) panic("vmapbuf: null page frame"); #ifdef M68K_VAC pmap_enter(kpmap, kva, pa, VM_PROT_READ | VM_PROT_WRITE, PMAP_WIRED); #else pmap_kenter_pa(kva, pa, VM_PROT_READ | VM_PROT_WRITE, 0); #endif uva += PAGE_SIZE; kva += PAGE_SIZE; len -= PAGE_SIZE; } while (len); pmap_update(kpmap); return 0; }
static void grfiv_attach(struct device *parent, struct device *self, void *aux) { struct obio_attach_args *oa = (struct obio_attach_args *)aux; struct grfbus_softc *sc; struct grfmode *gm; u_long base, length; u_int32_t vbase1, vbase2; sc = (struct grfbus_softc *)self; sc->card_id = 0; switch (current_mac_model->class) { case MACH_CLASSQ2: if (current_mac_model->machineid != MACH_MACLC575) { sc->sc_basepa = VALKYRIE_BASE; length = 0x00100000; /* 1MB */ if (sc->sc_basepa <= mac68k_video.mv_phys && mac68k_video.mv_phys < (sc->sc_basepa + length)) { sc->sc_fbofs = mac68k_video.mv_phys - sc->sc_basepa; } else { sc->sc_basepa = m68k_trunc_page(mac68k_video.mv_phys); sc->sc_fbofs = m68k_page_offset(mac68k_video.mv_phys); length = mac68k_video.mv_len + sc->sc_fbofs; } printf(" @ %lx: Valkyrie video subsystem\n", sc->sc_basepa + sc->sc_fbofs); break; } /* See note in grfiv_match() */ /*FALLTHROUGH*/ case MACH_CLASSQ: base = DAFB_CONTROL_BASE; sc->sc_tag = oa->oa_tag; if (bus_space_map(sc->sc_tag, base, 0x20, 0, &sc->sc_regh)) { printf(": failed to map DAFB register space\n"); return; } sc->sc_basepa = DAFB_BASE; length = 0x00100000; /* 1MB */ /* Compute the current frame buffer offset */ vbase1 = bus_space_read_4(sc->sc_tag, sc->sc_regh, 0x0) & 0xfff; #if 1 /* * XXX The following exists because the DAFB v7 in these * systems doesn't return reasonable values to use for fbofs. * Ken'ichi Ishizaka gets credit for this hack. (sar 19990426) * (Does this get us the correct result for _all_ DAFB- * equipped systems and monitor combinations? It seems * possible, if not likely...) */ switch (current_mac_model->machineid) { case MACH_MACLC475: case MACH_MACLC475_33: case MACH_MACLC575: case MACH_MACQ605: case MACH_MACQ605_33: vbase1 &= 0x3f; break; } #endif vbase2 = bus_space_read_4(sc->sc_tag, sc->sc_regh, 0x4) & 0xf; sc->sc_fbofs = (vbase1 << 9) | (vbase2 << 5); printf(" @ %lx: DAFB video subsystem, monitor sense %x\n", sc->sc_basepa + sc->sc_fbofs, (bus_space_read_4(sc->sc_tag, sc->sc_regh, 0x1c) & 0x7)); bus_space_unmap(sc->sc_tag, sc->sc_regh, 0x20); break; case MACH_CLASSAV: sc->sc_basepa = CIVIC_BASE; length = 0x00200000; /* 2MB */ if (mac68k_video.mv_phys >= sc->sc_basepa && mac68k_video.mv_phys < (sc->sc_basepa + length)) { sc->sc_fbofs = mac68k_video.mv_phys - sc->sc_basepa; } else { sc->sc_basepa = m68k_trunc_page(mac68k_video.mv_phys); sc->sc_fbofs = m68k_page_offset(mac68k_video.mv_phys); length = mac68k_video.mv_len + sc->sc_fbofs; } printf(" @ %lx: CIVIC video subsystem\n", sc->sc_basepa + sc->sc_fbofs); break; case MACH_CLASSIIci: case MACH_CLASSIIsi: sc->sc_basepa = m68k_trunc_page(mac68k_video.mv_phys); sc->sc_fbofs = m68k_page_offset(mac68k_video.mv_phys); length = mac68k_video.mv_len + sc->sc_fbofs; printf(" @ %lx: RBV video subsystem, ", sc->sc_basepa + sc->sc_fbofs); switch (via2_reg(rMonitor) & RBVMonitorMask) { case RBVMonIDBWP: printf("15\" monochrome portrait"); break; case RBVMonIDRGB12: printf("12\" color"); break; case RBVMonIDRGB15: printf("15\" color"); break; case RBVMonIDStd: printf("Macintosh II"); break; default: printf("unrecognized"); break; } printf(" display\n"); break; default: sc->sc_basepa = m68k_trunc_page(mac68k_video.mv_phys); sc->sc_fbofs = m68k_page_offset(mac68k_video.mv_phys); length = mac68k_video.mv_len + sc->sc_fbofs; printf(" @ %lx: On-board video\n", sc->sc_basepa + sc->sc_fbofs); break; } if (bus_space_map(sc->sc_tag, sc->sc_basepa, length, 0, &sc->sc_handle)) { printf("%s: failed to map video RAM\n", sc->sc_dev.dv_xname); return; } if (sc->sc_basepa <= mac68k_video.mv_phys && mac68k_video.mv_phys < (sc->sc_basepa + length)) { /* XXX Hack */ mac68k_video.mv_kvaddr = sc->sc_handle.base + sc->sc_fbofs; } gm = &(sc->curr_mode); gm->mode_id = 0; gm->psize = mac68k_video.mv_depth; gm->ptype = 0; gm->width = mac68k_video.mv_width; gm->height = mac68k_video.mv_height; gm->rowbytes = mac68k_video.mv_stride; gm->hres = 80; /* XXX hack */ gm->vres = 80; /* XXX hack */ gm->fbsize = gm->height * gm->rowbytes; gm->fbbase = (void *)sc->sc_handle.base; /* XXX yet another hack */ gm->fboff = sc->sc_fbofs; /* Perform common video attachment. */ grf_establish(sc, NULL, grfiv_mode); }
/*ARGSUSED*/ void trap(struct trapframe *tf, int type, u_int code, u_int v) { struct lwp *l; struct proc *p; struct pcb *pcb; ksiginfo_t ksi; int tmp; int rv; u_quad_t sticks; void *onfault; curcpu()->ci_data.cpu_ntrap++; l = curlwp; p = l->l_proc; pcb = lwp_getpcb(l); onfault = pcb->pcb_onfault; KSI_INIT_TRAP(&ksi); ksi.ksi_trap = type & ~T_USER; KASSERT(pcb != NULL); if (USERMODE(tf->tf_sr)) { type |= T_USER; sticks = p->p_sticks; l->l_md.md_regs = tf->tf_regs; LWP_CACHE_CREDS(l, p); } else { sticks = 0; /* XXX: Detect trap recursion? */ } switch (type) { default: dopanic: printf("trap type=0x%x, code=0x%x, v=0x%x\n", type, code, v); /* * Let the kernel debugger see the trap frame that * caused us to panic. This is a convenience so * one can see registers at the point of failure. */ tmp = splhigh(); #ifdef KGDB /* If connected, step or cont returns 1 */ if (kgdb_trap(type, tf)) goto kgdb_cont; #endif #ifdef DDB (void) kdb_trap(type, (db_regs_t *) tf); #endif #ifdef KGDB kgdb_cont: #endif splx(tmp); if (panicstr) { /* * Note: panic is smart enough to do: * boot(RB_AUTOBOOT | RB_NOSYNC, NULL) * if we call it again. */ panic("trap during panic!"); } regdump(tf, 128); type &= ~T_USER; if ((u_int)type < trap_types) panic(trap_type[type]); panic("trap type 0x%x", type); case T_BUSERR: /* kernel bus error */ if (onfault == NULL) goto dopanic; rv = EFAULT; /*FALLTHROUGH*/ copyfault: /* * If we have arranged to catch this fault in any of the * copy to/from user space routines, set PC to return to * indicated location and set flag informing buserror code * that it may need to clean up stack frame. */ tf->tf_stackadj = exframesize[tf->tf_format]; tf->tf_format = tf->tf_vector = 0; tf->tf_pc = (int)onfault; tf->tf_regs[D0] = rv; goto done; case T_BUSERR|T_USER: /* bus error */ case T_ADDRERR|T_USER: /* address error */ ksi.ksi_addr = (void *)v; ksi.ksi_signo = SIGBUS; ksi.ksi_code = (type == (T_BUSERR|T_USER)) ? BUS_OBJERR : BUS_ADRERR; break; case T_COPERR: /* kernel coprocessor violation */ case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */ case T_FMTERR: /* ...just in case... */ /* * The user has most likely trashed the RTE or FP state info * in the stack frame of a signal handler. */ printf("pid %d: kernel %s exception\n", p->p_pid, type==T_COPERR ? "coprocessor" : "format"); type |= T_USER; mutex_enter(p->p_lock); SIGACTION(p, SIGILL).sa_handler = SIG_DFL; sigdelset(&p->p_sigctx.ps_sigignore, SIGILL); sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL); sigdelset(&l->l_sigmask, SIGILL); mutex_exit(p->p_lock); ksi.ksi_signo = SIGILL; ksi.ksi_addr = (void *)(int)tf->tf_format; ksi.ksi_code = (type == T_COPERR) ? ILL_COPROC : ILL_ILLOPC; break; case T_COPERR|T_USER: /* user coprocessor violation */ /* What is a proper response here? */ ksi.ksi_signo = SIGFPE; ksi.ksi_code = FPE_FLTINV; break; case T_FPERR|T_USER: /* 68881 exceptions */ /* * We pass along the 68881 status register which locore stashed * in code for us. */ ksi.ksi_signo = SIGFPE; ksi.ksi_code = fpsr2siginfocode(code); break; case T_FPEMULI: /* FPU faults in supervisor mode */ case T_FPEMULD: if (nofault) /* Doing FPU probe? */ longjmp(nofault); goto dopanic; case T_FPEMULI|T_USER: /* unimplemented FP instruction */ case T_FPEMULD|T_USER: /* unimplemented FP data type */ #ifdef FPU_EMULATE if (fpu_emulate(tf, &pcb->pcb_fpregs, &ksi) == 0) ; /* XXX - Deal with tracing? (tf->tf_sr & PSL_T) */ #else uprintf("pid %d killed: no floating point support\n", p->p_pid); ksi.ksi_signo = SIGILL; ksi.ksi_code = ILL_ILLOPC; #endif break; case T_ILLINST|T_USER: /* illegal instruction fault */ case T_PRIVINST|T_USER: /* privileged instruction fault */ ksi.ksi_addr = (void *)(int)tf->tf_format; ksi.ksi_signo = SIGILL; ksi.ksi_code = (type == (T_PRIVINST|T_USER)) ? ILL_PRVOPC : ILL_ILLOPC; break; case T_ZERODIV|T_USER: /* Divide by zero */ ksi.ksi_code = FPE_FLTDIV; case T_CHKINST|T_USER: /* CHK instruction trap */ case T_TRAPVINST|T_USER: /* TRAPV instruction trap */ ksi.ksi_addr = (void *)(int)tf->tf_format; ksi.ksi_signo = SIGFPE; break; /* * XXX: Trace traps are a nightmare. * * HP-UX uses trap #1 for breakpoints, * NetBSD/m68k uses trap #2, * SUN 3.x uses trap #15, * DDB and KGDB uses trap #15 (for kernel breakpoints; * handled elsewhere). * * NetBSD and HP-UX traps both get mapped by locore.s into T_TRACE. * SUN 3.x traps get passed through as T_TRAP15 and are not really * supported yet. * * XXX: We should never get kernel-mode T_TRAP15 * XXX: because locore.s now gives them special treatment. */ case T_TRAP15: /* kernel breakpoint */ tf->tf_sr &= ~PSL_T; goto done; case T_TRACE|T_USER: /* user trace trap */ #ifdef COMPAT_SUNOS /* * SunOS uses Trap #2 for a "CPU cache flush" * Just flush the on-chip caches and return. * XXX - Too bad NetBSD uses trap 2... */ if (p->p_emul == &emul_sunos) { /* get out fast */ goto done; } #endif /* FALLTHROUGH */ case T_TRACE: /* tracing a trap instruction */ case T_TRAP15|T_USER: /* SUN user trace trap */ tf->tf_sr &= ~PSL_T; ksi.ksi_signo = SIGTRAP; break; case T_ASTFLT: /* system async trap, cannot happen */ goto dopanic; case T_ASTFLT|T_USER: /* user async trap */ astpending = 0; /* T_SSIR is not used on a Sun2. */ if (l->l_pflag & LP_OWEUPC) { l->l_pflag &= ~LP_OWEUPC; ADDUPROF(l); } if (curcpu()->ci_want_resched) preempt(); goto douret; case T_MMUFLT: /* kernel mode page fault */ /* Hacks to avoid calling VM code from debugger. */ #ifdef DDB if (db_recover != 0) goto dopanic; #endif #ifdef KGDB if (kgdb_recover != 0) goto dopanic; #endif /* * If we were doing profiling ticks or other user mode * stuff from interrupt code, Just Say No. */ if (onfault == (void *)fubail || onfault == (void *)subail) { #ifdef DEBUG if (mmudebug & MDB_CPFAULT) { printf("trap: copyfault fu/su bail\n"); Debugger(); } #endif rv = EFAULT; goto copyfault; } /*FALLTHROUGH*/ case T_MMUFLT|T_USER: { /* page fault */ vaddr_t va; struct vmspace *vm = p->p_vmspace; struct vm_map *map; vm_prot_t ftype; extern struct vm_map *kernel_map; #ifdef DEBUG if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) printf("trap: T_MMUFLT pid=%d, code=0x%x, v=0x%x, pc=0x%x, sr=0x%x\n", p->p_pid, code, v, tf->tf_pc, tf->tf_sr); #endif /* * It is only a kernel address space fault iff: * 1. (type & T_USER) == 0 and: (2 or 3) * 2. pcb_onfault not set or * 3. pcb_onfault set but supervisor space data fault * The last can occur during an exec() copyin where the * argument space is lazy-allocated. */ map = &vm->vm_map; if ((type & T_USER) == 0) { /* supervisor mode fault */ if (onfault == NULL || KDFAULT(code)) map = kernel_map; } if (WRFAULT(code)) ftype = VM_PROT_WRITE; else ftype = VM_PROT_READ; va = m68k_trunc_page((vaddr_t)v); /* * Need to resolve the fault. * * We give the pmap code a chance to resolve faults by * reloading translations that it was forced to unload. * This function does that, and calls vm_fault if it * could not resolve the fault by reloading the MMU. * This function may also, for example, disallow any * faults in the kernel text segment, etc. */ pcb->pcb_onfault = NULL; rv = _pmap_fault(map, va, ftype); pcb->pcb_onfault = onfault; #ifdef DEBUG if (rv && MDB_ISPID(p->p_pid)) { printf("vm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n", map, va, ftype, rv); if (mmudebug & MDB_WBFAILED) Debugger(); } #endif /* DEBUG */ /* * If this was a stack access we keep track of the maximum * accessed stack size. Also, if vm_fault gets a protection * failure it is due to accessing the stack region outside * the current limit and we need to reflect that as an access * error. */ if (rv == 0) { if (map != kernel_map && (void *)va >= vm->vm_maxsaddr) uvm_grow(p, va); if ((type & T_USER) == 0 && ucas_ras_check(tf)) { return; } goto finish; } if (rv == EACCES) { ksi.ksi_code = SEGV_ACCERR; rv = EFAULT; } else ksi.ksi_code = SEGV_MAPERR; if ((type & T_USER) == 0) { /* supervisor mode fault */ if (onfault) { #ifdef DEBUG if (mmudebug & MDB_CPFAULT) { printf("trap: copyfault pcb_onfault\n"); Debugger(); } #endif goto copyfault; } printf("vm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n", map, va, ftype, rv); goto dopanic; } ksi.ksi_addr = (void *)v; switch (rv) { case ENOMEM: printf("UVM: pid %d (%s), uid %d killed: out of swap\n", p->p_pid, p->p_comm, l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1); ksi.ksi_signo = SIGKILL; break; case EINVAL: ksi.ksi_signo = SIGBUS; ksi.ksi_code = BUS_ADRERR; break; case EACCES: ksi.ksi_signo = SIGSEGV; ksi.ksi_code = SEGV_ACCERR; break; default: ksi.ksi_signo = SIGSEGV; ksi.ksi_code = SEGV_MAPERR; break; } break; } /* T_MMUFLT */ } /* switch */ finish: /* If trap was from supervisor mode, just return. */ if ((type & T_USER) == 0) goto done; /* Post a signal if necessary. */ if (ksi.ksi_signo) trapsignal(l, &ksi); douret: userret(l, tf, sticks); done:; /* XXX: Detect trap recursion? */ }