#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/user.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/resource.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sys/syscall_mi.h>
#include <sys/syslog.h>
#include <uvm/uvm_extern.h>
#include <machine/cpu.h>
#include <machine/ctlreg.h>
#include <machine/fsr.h>
#include <machine/trap.h>
#include <machine/instr.h>
#include <machine/pmap.h>
#ifdef DDB
#include <machine/db_machdep.h>
#else
#include <machine/frame.h>
#endif
#include <sparc64/fpu/fpu_extern.h>
#include <sparc64/sparc64/cache.h>
const struct fpstate initfpstate = {
{ ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0 }
};
static const char T[] = "*trap";
const char *trap_type[] = {
"ast",
"power on reset",
"watchdog reset",
"externally initiated reset",
"software initiated reset",
"RED state exception",
T, T,
"instruction access exception",
"*instruction MMU miss",
"instruction access error",
T, T, T, T, T,
"illegal instruction",
"privileged opcode",
"*unimplemented LDD",
"*unimplemented STD",
T, T, T, T,
T, T, T, T, T, T, T, T,
"fp disabled",
"fp exception ieee 754",
"fp exception other",
"tag overflow",
"clean window",
T, T, T,
"division by zero",
"*internal processor error",
T, T, T, T, T, T,
"data access exception",
"*data access MMU miss",
"data access error",
"*data access protection",
"mem address not aligned",
"LDDF mem address not aligned",
"STDF mem address not aligned",
"privileged action",
"LDQF mem address not aligned",
"STQF mem address not aligned",
T, T, T, T, T, T,
"*async data error",
"level 1 int",
"level 2 int",
"level 3 int",
"level 4 int",
"level 5 int",
"level 6 int",
"level 7 int",
"level 8 int",
"level 9 int",
"level 10 int",
"level 11 int",
"level 12 int",
"level 13 int",
"level 14 int",
"level 15 int",
T, T, T, T, T, T, T, T,
T, T, T, T, T, T, T, T,
"+interrupt vector",
"+PA_watchpoint",
"+VA_watchpoint",
"+corrected ECC error",
"+fast instruction access MMU miss",
T, T, T,
"+fast data access MMU miss",
T, T, T,
"+fast data access protection",
T, T, T,
T, T, T, T, T, T, T, T,
T, T, T, T, T, T, T, T,
"spill 0 normal",
T, T, T,
"spill 1 normal",
T, T, T,
"spill 2 normal",
T, T, T,
"spill 3 normal",
T, T, T,
"spill 4 normal",
T, T, T,
"spill 5 normal",
T, T, T,
"spill 6 normal",
T, T, T,
"spill 7 normal",
T, T, T,
"spill 0 other",
T, T, T,
"spill 1 other",
T, T, T,
"spill 2 other",
T, T, T,
"spill 3 other",
T, T, T,
"spill 4 other",
T, T, T,
"spill 5 other",
T, T, T,
"spill 6 other",
T, T, T,
"spill 7 other",
T, T, T,
"fill 0 normal",
T, T, T,
"fill 1 normal",
T, T, T,
"fill 2 normal",
T, T, T,
"fill 3 normal",
T, T, T,
"fill 4 normal",
T, T, T,
"fill 5 normal",
T, T, T,
"fill 6 normal",
T, T, T,
"fill 7 normal",
T, T, T,
"fill 0 other",
T, T, T,
"fill 1 other",
T, T, T,
"fill 2 other",
T, T, T,
"fill 3 other",
T, T, T,
"fill 4 other",
T, T, T,
"fill 5 other",
T, T, T,
"fill 6 other",
T, T, T,
"fill 7 other",
T, T, T,
"syscall",
"breakpoint",
"zero divide",
"flush windows",
"clean windows",
"range check",
"fix align",
"integer overflow",
"svr4 syscall",
"4.4 syscall",
"kgdb exec",
T, T, T, T, T,
T, T, T, T, T, T, T, T,
T, T, T, T, T, T, T, T,
"svr4 getcc",
"svr4 setcc",
"svr4 getpsr",
"svr4 setpsr",
"svr4 gethrtime",
"svr4 gethrvtime",
T,
"svr4 gethrestime",
T, T, T, T, T, T, T, T,
T, T,
"get condition codes",
"set condition codes",
T, T, T, T,
T, T, T, T, T, T, T, T,
T, T, T, T, T, T, T, T,
T, T, T, T, T, T, T, T,
T, T, T, T, T, T, T, T,
T, T, T, T, T, T, T, T,
T, T, T, T,
"SVID syscall64",
"SPARC Intl syscall64",
"OS vendor spec syscall",
"HW OEM syscall",
"ret from deferred trap",
};
#define N_TRAP_TYPES (sizeof trap_type / sizeof *trap_type)
static inline void share_fpu(struct proc *, struct trapframe *);
void trap(struct trapframe *tf, unsigned type, vaddr_t pc, long tstate);
void data_access_fault(struct trapframe *tf, unsigned type, vaddr_t pc,
vaddr_t va, vaddr_t sfva, u_long sfsr);
void data_access_error(struct trapframe *tf, unsigned type,
vaddr_t afva, u_long afsr, vaddr_t sfva, u_long sfsr);
void text_access_fault(struct trapframe *tf, unsigned type,
vaddr_t pc, u_long sfsr);
void text_access_error(struct trapframe *tf, unsigned type,
vaddr_t pc, u_long sfsr, vaddr_t afva, u_long afsr);
void syscall(struct trapframe *, register_t code, register_t pc);
int copyinsn(struct proc *p, vaddr_t uva, int *insn);
static inline void
share_fpu(struct proc *p, struct trapframe *tf)
{
if (!(tf->tf_tstate & TSTATE_PRIV) &&
(tf->tf_tstate & TSTATE_PEF) && fpproc != p)
tf->tf_tstate &= ~TSTATE_PEF;
}
void
trap(struct trapframe *tf, unsigned type, vaddr_t pc, long tstate)
{
struct proc *p;
struct pcb *pcb;
int pstate = (tstate>>TSTATE_PSTATE_SHIFT);
u_int64_t s;
int64_t n;
union sigval sv;
sv.sival_ptr = (void *)pc;
#define ADVANCE (n = tf->tf_npc, tf->tf_pc = n, tf->tf_npc = n + 4)
atomic_inc_int(&uvmexp.traps);
if (pstate & PSTATE_PRIV) {
#ifdef DDB
if (type == T_BREAKPOINT) {
write_all_windows();
if (db_ktrap(type, tf)) {
return;
}
}
if (type == T_PA_WATCHPT || type == T_VA_WATCHPT) {
if (db_ktrap(type, tf)) {
return;
}
}
#endif
if (type == T_FPDISABLED) {
struct proc *newfpproc;
if (CLKF_INTR((struct clockframe *)tf) || !curproc)
newfpproc = &proc0;
else {
newfpproc = curproc;
if (newfpproc->p_md.md_fpstate)
fpusave_proc(newfpproc, 1);
}
if (fpproc != newfpproc) {
s = intr_disable();
if (fpproc != NULL) {
savefpstate(fpproc->p_md.md_fpstate);
fpproc = NULL;
}
intr_restore(s);
if (newfpproc->p_md.md_fpstate != 0) {
fpproc = newfpproc;
loadfpstate(fpproc->p_md.md_fpstate);
} else
fpproc = NULL;
}
tf->tf_tstate |= (PSTATE_PEF<<TSTATE_PSTATE_SHIFT);
return;
}
if (type != T_SPILL_N_NORM && type != T_FILL_N_NORM)
goto dopanic;
}
if ((p = curproc) == NULL)
p = &proc0;
pcb = &p->p_addr->u_pcb;
p->p_md.md_tf = tf;
refreshcreds(p);
switch (type) {
default:
if (type < 0x100) {
dopanic:
panic("trap type 0x%x (%s): pc=%lx npc=%lx pstate=%b",
type, type < N_TRAP_TYPES ? trap_type[type] : T,
pc, (long)tf->tf_npc, pstate, PSTATE_BITS);
}
trapsignal(p, SIGILL, type, ILL_ILLOPC, sv);
break;
case T_AST:
p->p_md.md_astpending = 0;
atomic_inc_int(&uvmexp.softs);
mi_ast(p, curcpu()->ci_want_resched);
break;
case T_RWRET:
write_user_windows();
if (rwindow_save(p) == -1) {
trapsignal(p, SIGILL, 0, ILL_BADSTK, sv);
}
break;
case T_ILLINST:
{
union instr ins;
if (copyinsn(p, pc, &ins.i_int) != 0) {
trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
break;
}
if (ins.i_any.i_op == IOP_mem &&
(ins.i_op3.i_op3 == IOP3_LDQF ||
ins.i_op3.i_op3 == IOP3_STQF ||
ins.i_op3.i_op3 == IOP3_LDQFA ||
ins.i_op3.i_op3 == IOP3_STQFA)) {
if (emul_qf(ins.i_int, p, sv, tf))
ADVANCE;
break;
}
if (ins.i_any.i_op == IOP_reg &&
ins.i_op3.i_op3 == IOP3_POPC &&
ins.i_op3.i_rs1 == 0) {
if (emul_popc(ins.i_int, p, sv, tf))
ADVANCE;
break;
}
trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
break;
}
case T_INST_EXCEPT:
case T_TEXTFAULT:
case T_PRIVINST:
case T_PRIVACT:
trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
break;
case T_FPDISABLED: {
struct fpstate *fs = p->p_md.md_fpstate;
if (fs == NULL) {
KERNEL_LOCK();
fs = malloc((sizeof *fs), M_SUBPROC, M_WAITOK);
*fs = initfpstate;
p->p_md.md_fpstate = fs;
KERNEL_UNLOCK();
}
if (fpproc != p) {
fpusave_proc(p, 1);
s = intr_disable();
if (fpproc != NULL)
savefpstate(fpproc->p_md.md_fpstate);
loadfpstate(fs);
fpproc = p;
intr_restore(s);
atomic_inc_int(&uvmexp.fpswtch);
}
tf->tf_tstate |= (PSTATE_PEF<<TSTATE_PSTATE_SHIFT);
sparc_wr(fprs, FPRS_FEF, 0);
break;
}
case T_LDQF_ALIGN:
case T_STQF_ALIGN:
{
union instr ins;
if (copyinsn(p, pc, &ins.i_int) != 0) {
trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
break;
}
if (ins.i_any.i_op == IOP_mem &&
(ins.i_op3.i_op3 == IOP3_LDQF ||
ins.i_op3.i_op3 == IOP3_STQF ||
ins.i_op3.i_op3 == IOP3_LDQFA ||
ins.i_op3.i_op3 == IOP3_STQFA)) {
if (emul_qf(ins.i_int, p, sv, tf))
ADVANCE;
} else {
trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
}
break;
}
case T_SPILL_N_NORM:
case T_FILL_N_NORM:
KERNEL_LOCK();
sigexit(p, SIGKILL);
break;
case T_ALIGN:
case T_LDDF_ALIGN:
case T_STDF_ALIGN:
if (p->p_addr->u_pcb.pcb_onfault) {
tf->tf_pc = (vaddr_t)p->p_addr->u_pcb.pcb_onfault;
tf->tf_npc = tf->tf_pc + 4;
break;
}
trapsignal(p, SIGBUS, 0, BUS_ADRALN, sv);
break;
case T_FP_IEEE_754:
case T_FP_OTHER:
{
union instr ins;
if (p != fpproc)
panic("fpe without being the FP user");
s = intr_disable();
savefpstate(p->p_md.md_fpstate);
fpproc = NULL;
intr_restore(s);
if (type == T_FP_OTHER) {
(void)copyinsn(p, pc, &ins.i_int);
} else
ins.i_int = 0;
ADVANCE;
fpu_cleanup(p, p->p_md.md_fpstate, ins, sv);
break;
}
case T_TAGOF:
case T_BREAKPOINT:
trapsignal(p, SIGTRAP, 0, TRAP_BRKPT, sv);
break;
case T_DIV0:
ADVANCE;
trapsignal(p, SIGFPE, 0, FPE_INTDIV, sv);
break;
case T_CLEANWIN:
ADVANCE;
break;
case T_FLUSHWIN:
write_all_windows();
ADVANCE;
break;
case T_RANGECHECK:
ADVANCE;
trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
break;
case T_FIXALIGN:
ADVANCE;
trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
break;
case T_INTOF:
ADVANCE;
trapsignal(p, SIGFPE, FPE_INTOVF_TRAP, FPE_INTOVF, sv);
break;
}
userret(p);
share_fpu(p, tf);
#undef ADVANCE
}
int
rwindow_save(struct proc *p)
{
struct pcb *pcb = &p->p_addr->u_pcb;
int i;
for (i = 0; i < pcb->pcb_nsaved; i++) {
pcb->pcb_rw[i].rw_in[7] ^= pcb->pcb_wcookie;
if (copyout(&pcb->pcb_rw[i], (void *)(pcb->pcb_rwsp[i] + BIAS),
sizeof(struct rwindow)))
return (-1);
}
pcb->pcb_nsaved = 0;
return (0);
}
void
pmap_unuse_final(struct proc *p)
{
write_user_windows();
p->p_addr->u_pcb.pcb_nsaved = 0;
}
static inline int
accesstype(unsigned int type, u_long sfsr)
{
if (type == T_FDMMU_MISS || (sfsr & SFSR_FV) == 0)
return PROT_READ;
else if (sfsr & SFSR_W)
return PROT_WRITE;
return PROT_READ;
}
void
data_access_fault(struct trapframe *tf, unsigned type, vaddr_t pc,
vaddr_t addr, vaddr_t sfva, u_long sfsr)
{
struct proc *p = curproc;
vaddr_t va = trunc_page(addr);
vm_prot_t access_type = accesstype(type, sfsr);
vaddr_t onfault;
union sigval sv;
int signal, sicode, error;
atomic_inc_int(&uvmexp.traps);
if (p == NULL)
p = &proc0;
if (tf->tf_tstate & TSTATE_PRIV) {
#ifdef DDB
extern char Lfsprobe[];
if (p->p_addr->u_pcb.pcb_onfault == Lfsprobe)
goto kfault;
#endif
if (cold)
goto kfault;
if (!(addr & TLB_TAG_ACCESS_CTX)) {
error = uvm_fault(kernel_map, va, 0, access_type);
if (error == 0)
return;
goto kfault;
}
} else {
p->p_md.md_tf = tf;
refreshcreds(p);
if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
"[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
goto out;
}
onfault = (vaddr_t)p->p_addr->u_pcb.pcb_onfault;
p->p_addr->u_pcb.pcb_onfault = NULL;
error = uvm_fault(&p->p_vmspace->vm_map, (vaddr_t)va, 0, access_type);
p->p_addr->u_pcb.pcb_onfault = (void *)onfault;
if (error == 0) {
uvm_grow(p, va);
goto out;
}
if (tf->tf_tstate & TSTATE_PRIV) {
kfault:
onfault = (long)p->p_addr->u_pcb.pcb_onfault;
if (!onfault) {
(void) splhigh();
panic("kernel data fault: pc=%lx addr=%lx",
pc, addr);
}
tf->tf_pc = onfault;
tf->tf_npc = onfault + 4;
return;
}
if (type == T_FDMMU_MISS || (sfsr & SFSR_FV) == 0)
sv.sival_ptr = (void *)va;
else
sv.sival_ptr = (void *)sfva;
signal = SIGSEGV;
sicode = SEGV_MAPERR;
if (error == ENOMEM) {
printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
p->p_p->ps_pid, p->p_p->ps_comm,
p->p_ucred ? (int)p->p_ucred->cr_uid : -1);
signal = SIGKILL;
} else if (error == EACCES)
sicode = SEGV_ACCERR;
else if (error == EIO) {
signal = SIGBUS;
sicode = BUS_OBJERR;
}
trapsignal(p, signal, access_type, sicode, sv);
out:
if ((tf->tf_tstate & TSTATE_PRIV) == 0) {
userret(p);
share_fpu(p, tf);
}
}
void
data_access_error(struct trapframe *tf, unsigned type, vaddr_t afva,
u_long afsr, vaddr_t sfva, u_long sfsr)
{
struct proc *p = curproc;
u_long pc;
vaddr_t onfault;
union sigval sv;
atomic_inc_int(&uvmexp.traps);
if (p == NULL)
p = &proc0;
if (curcpu()->ci_pci_probe) {
curcpu()->ci_pci_fault = 1;
goto out;
}
pc = tf->tf_pc;
onfault = (long)p->p_addr->u_pcb.pcb_onfault;
printf("data error type %x sfsr=%lx sfva=%lx afsr=%lx afva=%lx tf=%p\n",
type, sfsr, sfva, afsr, afva, tf);
if (afsr == 0 && sfsr == 0) {
printf("data_access_error: no fault\n");
goto out;
}
if (tf->tf_tstate & TSTATE_PRIV) {
if (!onfault) {
(void) splhigh();
panic("data fault: pc=%lx addr=%lx sfsr=%lb",
(u_long)pc, (long)sfva, sfsr, SFSR_BITS);
}
if (afsr & ASFR_PRIV) {
panic("Privileged Async Fault: AFAR %p AFSR %lx\n%lb",
(void *)afva, afsr, afsr, AFSR_BITS);
}
tf->tf_pc = onfault;
tf->tf_npc = onfault + 4;
return;
}
sv.sival_ptr = (void *)pc;
trapsignal(p, SIGSEGV, PROT_READ | PROT_WRITE, SEGV_MAPERR, sv);
out:
if ((tf->tf_tstate & TSTATE_PRIV) == 0) {
userret(p);
share_fpu(p, tf);
}
}
void
text_access_fault(struct trapframe *tf, unsigned type, vaddr_t pc,
u_long sfsr)
{
struct proc *p = curproc;
vaddr_t va = trunc_page(pc);
vm_prot_t access_type = PROT_EXEC;
union sigval sv;
int signal, sicode, error;
atomic_inc_int(&uvmexp.traps);
if (p == NULL)
panic("text_access_fault: no curproc");
sv.sival_ptr = (void *)pc;
if (tf->tf_tstate & TSTATE_PRIV) {
(void) splhigh();
panic("kernel text_access_fault: pc=%lx va=%lx", pc, va);
}
p->p_md.md_tf = tf;
refreshcreds(p);
if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
"[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
goto out;
error = uvm_fault(&p->p_vmspace->vm_map, va, 0, access_type);
if (error == 0)
goto out;
signal = SIGSEGV;
sicode = SEGV_MAPERR;
if (error == EACCES)
sicode = SEGV_ACCERR;
else if (error == EIO) {
signal = SIGBUS;
sicode = BUS_OBJERR;
}
trapsignal(p, signal, access_type, sicode, sv);
out:
userret(p);
share_fpu(p, tf);
}
void
text_access_error(struct trapframe *tf, unsigned type, vaddr_t pc,
u_long sfsr, vaddr_t afva, u_long afsr)
{
struct proc *p = curproc;
vaddr_t va = trunc_page(pc);
vm_prot_t access_type = PROT_EXEC;
union sigval sv;
int signal, sicode, error;
atomic_inc_int(&uvmexp.traps);
if (p == NULL)
p = &proc0;
sv.sival_ptr = (void *)pc;
if ((afsr) != 0) {
printf("text_access_error: memory error...\n");
printf("type %d sfsr=%lx sfva=%lx afsr=%lx afva=%lx tf=%p\n",
type, sfsr, pc, afsr, afva, tf);
if (tf->tf_tstate & TSTATE_PRIV)
panic("text_access_error: kernel memory error");
trapsignal(p, SIGBUS, 0, BUS_ADRALN, sv);
}
if ((sfsr & SFSR_FV) == 0 || (sfsr & SFSR_FT) == 0)
goto out;
if (tf->tf_tstate & TSTATE_PRIV) {
(void) splhigh();
panic("kernel text error: pc=%lx sfsr=%lb", pc,
sfsr, SFSR_BITS);
}
p->p_md.md_tf = tf;
refreshcreds(p);
if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p),
"[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n",
uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial))
goto out;
error = uvm_fault(&p->p_vmspace->vm_map, va, 0, access_type);
if (error == 0)
goto out;
signal = SIGSEGV;
sicode = SEGV_MAPERR;
if (error == EACCES)
sicode = SEGV_ACCERR;
else if (error == EIO) {
signal = SIGBUS;
sicode = BUS_OBJERR;
}
trapsignal(p, signal, access_type, sicode, sv);
out:
if ((tf->tf_tstate & TSTATE_PRIV) == 0) {
userret(p);
share_fpu(p, tf);
}
}
void
syscall(struct trapframe *tf, register_t code, register_t pc)
{
const struct sysent *callp;
struct proc *p = curproc;
int error = ENOSYS, new;
register_t rval[2];
register_t *args;
if ((tf->tf_out[6] & 1) == 0)
sigexit(p, SIGILL);
atomic_inc_int(&uvmexp.syscalls);
#ifdef DIAGNOSTIC
if (tf->tf_tstate & TSTATE_PRIV)
panic("syscall from kernel");
if (curpcb != &p->p_addr->u_pcb)
panic("syscall: cpcb/ppcb mismatch");
if (tf != (struct trapframe *)((caddr_t)curpcb + USPACE) - 1)
panic("syscall: trapframe");
#endif
p->p_md.md_tf = tf;
new = code & SYSCALL_G2RFLAG;
code &= ~SYSCALL_G2RFLAG;
if (code <= 0 || code >= SYS_MAXSYSCALL)
goto bad;
callp = sysent + code;
args = (register_t *)&tf->tf_out[0];
rval[0] = 0;
rval[1] = 0;
error = mi_syscall(p, code, callp, args, rval);
switch (error) {
vaddr_t dest;
case 0:
tf->tf_out[0] = rval[0];
if (new) {
dest = tf->tf_global[2];
if (dest & 3) {
error = EINVAL;
goto bad;
}
} else {
tf->tf_tstate &= ~(((int64_t)(ICC_C|XCC_C))<<TSTATE_CCR_SHIFT);
dest = tf->tf_npc;
}
tf->tf_pc = dest;
tf->tf_npc = dest + 4;
break;
case ERESTART:
case EJUSTRETURN:
break;
default:
bad:
tf->tf_out[0] = error;
tf->tf_tstate |= (((int64_t)(ICC_C|XCC_C))<<TSTATE_CCR_SHIFT);
dest = tf->tf_npc;
tf->tf_pc = dest;
tf->tf_npc = dest + 4;
break;
}
mi_syscall_return(p, code, error, rval);
share_fpu(p, tf);
}
void
child_return(void *arg)
{
struct proc *p = arg;
struct trapframe *tf = p->p_md.md_tf;
vaddr_t dest;
if (tf->tf_global[1] & SYSCALL_G2RFLAG) {
dest = tf->tf_global[2];
} else {
dest = tf->tf_npc;
tf->tf_tstate &= ~(((int64_t)(ICC_C|XCC_C))<<TSTATE_CCR_SHIFT);
}
tf->tf_pc = dest;
tf->tf_npc = dest + 4;
tf->tf_out[0] = 0;
KERNEL_UNLOCK();
mi_child_return(p);
}
int
copyinsn(struct proc *p, vaddr_t uva, int *insn)
{
struct vm_map *map = &p->p_vmspace->vm_map;
int error = 0;
if (__predict_false((uva & 3) != 0))
return EFAULT;
do {
if (pmap_copyinsn(map->pmap, uva, (uint32_t *)insn) == 0)
break;
error = uvm_fault(map, trunc_page(uva), 0, PROT_EXEC);
} while (error == 0);
return error;
}