/* #define DEBUG_CONFIG */ pcireg_t mpc_conf_read(void *cpv, pcitag_t tag, int offset) { struct pcibr_config *cp = cpv; pcireg_t data; u_int32_t reg; int s; int daddr = 0; faultbuf env; void *oldh; if (offset & 3 || offset < 0 || offset >= 0x100) { #ifdef DEBUG_CONFIG printf ("pci_conf_read: bad reg %x\n", offset); #endif /* DEBUG_CONFIG */ return(~0); } reg = mpc_gen_config_reg(cpv, tag, offset); /* if invalid tag, return -1 */ if (reg == 0xffffffff) return(~0); if ((cp->config_type & 2) && (offset & 0x04)) daddr += 4; s = splhigh(); oldh = curpcb->pcb_onfault; if (setfault(&env)) { /* we faulted during the read? */ curpcb->pcb_onfault = oldh; splx(s); return 0xffffffff; } bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg); bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ data = bus_space_read_4(cp->lc_iot, cp->ioh_cfc, daddr); bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */ bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ curpcb->pcb_onfault = oldh; splx(s); #ifdef DEBUG_CONFIG if (!((offset == 0) && (data == 0xffffffff))) { unsigned int bus, dev, fcn; mpc_decompose_tag(cpv, tag, &bus, &dev, &fcn); printf("mpc_conf_read bus %x dev %x fcn %x offset %x", bus, dev, fcn, offset); printf(" daddr %x reg %x",daddr, reg); printf(" data %x\n", data); } #endif return(data); }
/* Call an RTAS method by token */ int rtas_call_method(cell_t token, int nargs, int nreturns, ...) { vm_offset_t argsptr; faultbuf env, *oldfaultbuf; va_list ap; struct { cell_t token; cell_t nargs; cell_t nreturns; cell_t args_n_results[12]; } args; int n, result; if (!rtas_exists() || nargs + nreturns > 12) return (-1); args.token = token; va_start(ap, nreturns); mtx_lock_spin(&rtas_mtx); rtas_bounce_offset = 0; args.nargs = nargs; args.nreturns = nreturns; for (n = 0; n < nargs; n++) args.args_n_results[n] = va_arg(ap, cell_t); argsptr = rtas_real_map(&args, sizeof(args)); /* Get rid of any stale machine checks that have been waiting. */ __asm __volatile ("sync; isync"); oldfaultbuf = curthread->td_pcb->pcb_onfault; if (!setfault(env)) { __asm __volatile ("sync"); result = rtascall(argsptr, rtas_private_data); __asm __volatile ("sync; isync"); } else { result = RTAS_HW_ERROR; } curthread->td_pcb->pcb_onfault = oldfaultbuf; __asm __volatile ("sync"); rtas_real_unmap(argsptr, &args, sizeof(args)); mtx_unlock_spin(&rtas_mtx); if (result < 0) return (result); for (n = nargs; n < nargs + nreturns; n++) *va_arg(ap, cell_t *) = args.args_n_results[n]; return (result); }
int copyoutstr(const void *kaddr, void *udaddr, size_t len, size_t *done) { struct pmap *pm = curproc->p_vmspace->vm_map.pmap; int rv, msr, pid, tmp, ctx; struct faultbuf env; if ((rv = setfault(&env))) { curpcb->pcb_onfault = NULL; /* XXXX -- len may be lost on a fault */ if (done) *done = len; return rv; } if (!(ctx = pm->pm_ctx)) { /* No context -- assign it one */ ctx_alloc(pm); ctx = pm->pm_ctx; } if (len) { __asm volatile("mtctr %3;" /* Set up counter */ "mfmsr %0;" /* Save MSR */ "li %1,0x20; " "andc %1,%0,%1; mtmsr %1;" /* Disable IMMU */ "mfpid %1;" /* Save old PID */ "sync; isync;" "li %3,0;" /* Clear len */ "1:" "mtpid %1;sync;" "lbz %2,0(%6); addi %6,%6,1;" /* Store kernel byte */ "sync; isync;" "mtpid %4; sync;" /* Load user ctx */ "stb %2,0(%5); dcbf 0,%5; addi %5,%5,1;" /* Load byte */ "sync; isync;" "addi %3,%3,1;" /* Inc len */ "or. %2,%2,%2;" "bdnzf 2,1b;" /* * while(ctr-- && !zero) */ "mtpid %1; mtmsr %0;" /* Restore PID, MSR */ "sync; isync;" : "=&r" (msr), "=&r" (pid), "=&r" (tmp), "+b" (len) : "r" (ctx), "b" (udaddr), "b" (kaddr)); } curpcb->pcb_onfault = NULL; if (done) *done = len; return 0; }
int badaddr_read(void *addr, size_t size, int *rptr) { struct thread *td; faultbuf env; int x; /* Get rid of any stale machine checks that have been waiting. */ __asm __volatile ("sync; isync"); td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = 0; __asm __volatile ("sync"); return (1); } __asm __volatile ("sync"); switch (size) { case 1: x = *(volatile int8_t *)addr; break; case 2: x = *(volatile int16_t *)addr; break; case 4: x = *(volatile int32_t *)addr; break; default: panic("badaddr: invalid size (%d)", size); } /* Make sure we took the machine check, if we caused one. */ __asm __volatile ("sync; isync"); td->td_pcb->pcb_onfault = 0; __asm __volatile ("sync"); /* To be sure. */ /* Use the value to avoid reorder. */ if (rptr) *rptr = x; return (0); }
static int badaddr(void *addr, size_t size) { struct thread *td; faultbuf env, *oldfaultbuf; int x; /* Get rid of any stale machine checks that have been waiting. */ __asm __volatile ("sync; isync"); td = curthread; oldfaultbuf = td->td_pcb->pcb_onfault; if (setfault(env)) { td->td_pcb->pcb_onfault = oldfaultbuf; __asm __volatile ("sync"); return 1; } __asm __volatile ("sync"); switch (size) { case 1: x = *(volatile int8_t *)addr; break; case 2: x = *(volatile int16_t *)addr; break; case 4: x = *(volatile int32_t *)addr; break; default: panic("badaddr: invalid size (%zd)", size); } /* Make sure we took the machine check, if we caused one. */ __asm __volatile ("sync; isync"); td->td_pcb->pcb_onfault = oldfaultbuf; __asm __volatile ("sync"); /* To be sure. */ return (0); }
int copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done) { struct thread *td; faultbuf env; const char *up; char *kp; size_t l; int rv, c; if (!is_uaddr(udaddr) || is_uaddr(kaddr)) return (EFAULT); td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; return (EFAULT); } kp = kaddr; up = udaddr; rv = ENAMETOOLONG; for (l = 0; len-- > 0; l++) { c = *up++; if (!(*kp++ = c)) { l++; rv = 0; break; } } if (done != NULL) { *done = l; } td->td_pcb->pcb_onfault = NULL; return (rv); }
int copyin(const void *udaddr, void *kaddr, size_t len) { struct thread *td; faultbuf env; if (!is_uaddr(udaddr) || is_uaddr(kaddr)) return (EFAULT); td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; return (EFAULT); } bcopy(udaddr, kaddr, len); td->td_pcb->pcb_onfault = NULL; return (0); }
int suword(void *addr, long word) { struct thread *td; faultbuf env; if (!is_uaddr(addr)) return (EFAULT); td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; return (EFAULT); } *(long *)addr = word; td->td_pcb->pcb_onfault = NULL; return (0); }
int subyte(void *addr, int byte) { struct thread *td; faultbuf env; if (!is_uaddr(addr)) return (EFAULT); td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; return (EFAULT); } *(char *)addr = (char)byte; td->td_pcb->pcb_onfault = NULL; return (0); }
int copyout(const void *kaddr, void *udaddr, size_t len) { struct thread *td; faultbuf env; if (!is_uaddr(udaddr)) return (EFAULT); td = PCPU_GET(curthread); if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; return (EFAULT); } bcopy(kaddr, udaddr, len); td->td_pcb->pcb_onfault = NULL; return (0); }
long fuword(const void *addr) { struct thread *td; faultbuf env; long val; if (!is_uaddr(addr)) return (EFAULT); td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; return (EFAULT); } val = *(const long *)addr; td->td_pcb->pcb_onfault = NULL; return (val); }
int fubyte(const void *addr) { struct thread *td; faultbuf env; int val; if (!is_uaddr(addr)) return (EFAULT); td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; return (EFAULT); } val = *(const u_char *)addr; td->td_pcb->pcb_onfault = NULL; return (val); }