#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.201 2023/10/05 19:41:05 ad Exp $");
#include "opt_ddb.h"
#include "opt_compat_sunos.h"
#include "opt_sparc_arch.h"
#include "opt_multiprocessor.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/kmem.h>
#include <sys/resource.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sys/syslog.h>
#include <sys/kauth.h>
#include <uvm/uvm_extern.h>
#include <sparc/sparc/asm.h>
#include <machine/cpu.h>
#include <machine/ctlreg.h>
#include <machine/trap.h>
#include <machine/instr.h>
#include <machine/pcb.h>
#include <machine/pmap.h>
#include <machine/userret.h>
#include <machine/locore.h>
#ifdef DDB
#include <machine/db_machdep.h>
#else
#include <machine/frame.h>
#endif
#ifdef COMPAT_SUNOS
#include <compat/sunos/sunos_exec.h>
#define SUNOS_MAXSADDR_SLOP (32 * 1024)
#endif
#include <sparc/fpu/fpu_extern.h>
#include <sparc/sparc/memreg.h>
#include <sparc/sparc/cpuvar.h>
#ifdef DEBUG
int rwindow_debug = 0;
#endif
struct fpstate initfpstate = {
.fs_reg = {
.fr_regs = {
~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,
},
.fr_fsr = 0,
},
.fs_qsize = 0,
.fs_queue = { {
.fq_addr = NULL,
.fq_instr = 0,
}, },
};
static const char T[] = "trap";
const char *trap_type[] = {
"ast",
"text fault",
"illegal instruction",
"privileged instruction",
"fp disabled",
"window overflow",
"window underflow",
"alignment fault",
"fp exception",
"data fault",
"tag overflow",
"watchpoint",
T, T, T, T, T,
"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",
"register access error",
"instruction access error",
T, T,
"cp disabled",
"unimplemented flush",
T, T,
"cp exception",
"data access error",
"hw zero divide",
"data store error",
"data access MMU miss",
T, T, T,
T, T, T, T, T, T, T, T,
T, T, T, T,
"insn access MMU miss",
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, T, T, T,
T, T, T, T, T, T, T, T,
T, T, T, T, T, 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",
};
#define N_TRAP_TYPES (sizeof trap_type / sizeof *trap_type)
void trap(unsigned, int, int, struct trapframe *);
void mem_access_fault(unsigned, int, u_int, int, int, struct trapframe *);
void mem_access_fault4m(unsigned, u_int, u_int, struct trapframe *);
int ignore_bogus_traps = 1;
void
trap(unsigned type, int psr, int pc, struct trapframe *tf)
{
struct proc *p;
struct lwp *l;
struct pcb *pcb;
int n, s;
char bits[64];
u_quad_t sticks;
ksiginfo_t ksi;
int code, sig;
#define ADVANCE (n = tf->tf_npc, tf->tf_pc = n, tf->tf_npc = n + 4)
curcpu()->ci_data.cpu_ntrap++;
if (psr & PSR_PS) {
#ifdef DDB
if (type == T_BREAKPOINT) {
write_all_windows();
if (kdb_trap(type, tf)) {
return;
}
}
#if defined(MULTIPROCESSOR)
if (type == T_DBPAUSE) {
write_all_windows();
ddb_suspend(tf);
ADVANCE;
return;
}
#endif
#endif
#ifdef DIAGNOSTIC
if (type == T_FLUSHWIN) {
write_all_windows();
ADVANCE;
return;
}
#endif
if (type == T_UNIMPLFLUSH) {
#if defined(MULTIPROCESSOR)
XCALL0(*cpuinfo.pure_vcache_flush, CPUSET_ALL);
#else
(*cpuinfo.pure_vcache_flush)();
#endif
ADVANCE;
return;
}
if (type == T_FPDISABLED && cold) {
ADVANCE;
return;
}
dopanic:
snprintb(bits, sizeof(bits), PSR_BITS, psr);
printf("trap type 0x%x: pc=0x%x npc=0x%x psr=%s\n",
type, pc, tf->tf_npc, bits);
#ifdef DDB
write_all_windows();
(void) kdb_trap(type, tf);
#endif
panic("%s", type < N_TRAP_TYPES ? trap_type[type] : T);
}
if ((l = curlwp) == NULL)
l = &lwp0;
p = l->l_proc;
sticks = p->p_sticks;
pcb = lwp_getpcb(l);
l->l_md.md_tf = tf;
#ifdef FPU_DEBUG
if (type != T_FPDISABLED && (tf->tf_psr & PSR_EF) != 0) {
if (cpuinfo.fplwp != l)
panic("FPU enabled but wrong proc (0) [l=%p, fwlp=%p]",
l, cpuinfo.fplwp);
savefpstate(l->l_md.md_fpstate);
l->l_md.md_fpu = NULL;
cpuinfo.fplwp = NULL;
tf->tf_psr &= ~PSR_EF;
setpsr(getpsr() & ~PSR_EF);
}
#endif
sig = 0;
switch (type) {
default:
if (type < 0x80) {
if (!ignore_bogus_traps)
goto dopanic;
snprintb(bits, sizeof(bits), PSR_BITS, psr);
printf("trap type 0x%x: pc=0x%x npc=0x%x psr=%s\n",
type, pc, tf->tf_npc, bits);
sig = SIGILL;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = ILL_ILLTRP;
ksi.ksi_addr = (void *)pc;
break;
}
#ifdef DIAGNOSTIC
if (type < 0x90 || type > 0x9f) {
uprintf("%s[%d]: unimplemented software trap 0x%x\n",
p->p_comm, p->p_pid, type);
}
#endif
sig = SIGILL;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = ILL_ILLTRP;
ksi.ksi_addr = (void *)pc;
break;
case T_AST:
break;
case T_UNIMPLFLUSH:
#if defined(MULTIPROCESSOR)
XCALL0(*cpuinfo.pure_vcache_flush, CPUSET_ALL);
#else
(*cpuinfo.pure_vcache_flush)();
#endif
ADVANCE;
break;
case T_ILLINST:
if ((sig = emulinstr(pc, tf)) == 0) {
ADVANCE;
break;
}
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = ILL_ILLOPC;
ksi.ksi_addr = (void *)pc;
break;
case T_PRIVINST:
sig = SIGILL;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = ILL_PRVOPC;
ksi.ksi_addr = (void *)pc;
break;
case T_FPDISABLED: {
struct fpstate *fs = l->l_md.md_fpstate;
#ifdef FPU_DEBUG
if ((tf->tf_psr & PSR_PS) != 0) {
printf("FPU fault from kernel mode, pc=%x\n", pc);
#ifdef DDB
Debugger();
#endif
}
#endif
if (fs == NULL) {
fs = kmem_alloc(sizeof(struct fpstate), KM_SLEEP);
*fs = initfpstate;
l->l_md.md_fpstate = fs;
}
if (!cpuinfo.fpupresent) {
#ifdef notyet
fpu_emulate(l, tf, fs);
#else
sig = SIGFPE;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = SI_NOINFO;
ksi.ksi_addr = (void *)pc;
#endif
break;
}
if (fs->fs_qsize) {
if ((code = fpu_cleanup(l, fs)) != 0) {
sig = SIGFPE;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = code;
ksi.ksi_addr = (void *)pc;
}
break;
}
if (cpuinfo.fplwp != l) {
struct cpu_info *cpi;
FPU_LOCK(s);
if (cpuinfo.fplwp != NULL) {
savefpstate(cpuinfo.fplwp->l_md.md_fpstate);
cpuinfo.fplwp->l_md.md_fpu = NULL;
}
if ((cpi = l->l_md.md_fpu) != NULL) {
if (cpi->ci_cpuid == cpuinfo.ci_cpuid)
panic("FPU(%d): state for %p",
cpi->ci_cpuid, l);
#if defined(MULTIPROCESSOR)
XCALL1(ipi_savefpstate, fs, 1 << cpi->ci_cpuid);
#endif
cpi->fplwp = NULL;
}
loadfpstate(fs);
cpuinfo.fplwp = l;
l->l_md.md_fpu = curcpu();
FPU_UNLOCK(s);
}
tf->tf_psr |= PSR_EF;
break;
}
case T_WINOF:
if (rwindow_save(l)) {
mutex_enter(p->p_lock);
sigexit(l, SIGILL);
}
break;
#define read_rw(src, dst) \
copyin((void *)(src), (void *)(dst), sizeof(struct rwindow))
case T_RWRET:
if (pcb->pcb_uw || pcb->pcb_nsaved)
panic("trap T_RWRET 1");
#ifdef DEBUG
if (rwindow_debug)
printf("cpu%d:%s[%d]: rwindow: pcb<-stack: 0x%x\n",
cpuinfo.ci_cpuid, p->p_comm, p->p_pid,
tf->tf_out[6]);
#endif
if (read_rw(tf->tf_out[6], &pcb->pcb_rw[0])) {
mutex_enter(p->p_lock);
sigexit(l, SIGILL);
}
if (pcb->pcb_nsaved)
panic("trap T_RWRET 2");
pcb->pcb_nsaved = -1;
break;
case T_WINUF:
#ifdef DEBUG
if (rwindow_debug)
printf("cpu%d:%s[%d]: rwindow: T_WINUF 0: pcb<-stack: 0x%x\n",
cpuinfo.ci_cpuid, p->p_comm, p->p_pid,
tf->tf_out[6]);
#endif
write_user_windows();
if (rwindow_save(l) || read_rw(tf->tf_out[6], &pcb->pcb_rw[0])) {
mutex_enter(p->p_lock);
sigexit(l, SIGILL);
}
#ifdef DEBUG
if (rwindow_debug)
printf("cpu%d:%s[%d]: rwindow: T_WINUF 1: pcb<-stack: 0x%x\n",
cpuinfo.ci_cpuid, p->p_comm, p->p_pid,
pcb->pcb_rw[0].rw_in[6]);
#endif
if (read_rw(pcb->pcb_rw[0].rw_in[6], &pcb->pcb_rw[1])) {
mutex_enter(p->p_lock);
sigexit(l, SIGILL);
}
if (pcb->pcb_nsaved)
panic("trap T_WINUF");
pcb->pcb_nsaved = -1;
break;
case T_ALIGN:
if ((p->p_md.md_flags & MDP_FIXALIGN) != 0) {
n = fixalign(l, tf, NULL);
if (n == 0) {
ADVANCE;
break;
}
}
sig = SIGBUS;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = BUS_ADRALN;
fixalign(l, tf, &ksi.ksi_addr);
break;
case T_FPE:
if (l != cpuinfo.fplwp)
panic("fpe without being the FP user");
FPU_LOCK(s);
savefpstate(l->l_md.md_fpstate);
cpuinfo.fplwp = NULL;
l->l_md.md_fpu = NULL;
FPU_UNLOCK(s);
if ((code = fpu_cleanup(l, l->l_md.md_fpstate)) != 0) {
sig = SIGFPE;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = code;
ksi.ksi_addr = (void *)pc;
}
#if 0
ADVANCE;
#endif
break;
case T_TAGOF:
sig = SIGEMT;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = SI_NOINFO;
ksi.ksi_addr = (void *)pc;
break;
case T_CPDISABLED:
sig = SIGILL;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = ILL_COPROC;
ksi.ksi_addr = (void *)pc;
break;
case T_BREAKPOINT:
sig = SIGTRAP;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = TRAP_BRKPT;
ksi.ksi_addr = (void *)pc;
break;
case T_DIV0:
case T_IDIV0:
ADVANCE;
sig = SIGFPE;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = FPE_INTDIV;
ksi.ksi_addr = (void *)pc;
break;
case T_FLUSHWIN:
write_user_windows();
#ifdef probably_slower_since_this_is_usually_false
if (pcb->pcb_nsaved && rwindow_save(p)) {
mutex_enter(p->p_lock);
sigexit(l, SIGILL);
}
#endif
ADVANCE;
break;
case T_CLEANWIN:
uprintf("T_CLEANWIN\n");
ADVANCE;
break;
case T_RANGECHECK:
uprintf("T_RANGECHECK\n");
ADVANCE;
sig = SIGILL;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = ILL_ILLOPN;
ksi.ksi_addr = (void *)pc;
break;
case T_FIXALIGN:
#ifdef DEBUG_ALIGN
uprintf("T_FIXALIGN\n");
#endif
p->p_md.md_flags |= MDP_FIXALIGN;
ADVANCE;
break;
case T_INTOF:
uprintf("T_INTOF\n");
ADVANCE;
sig = SIGFPE;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = FPE_INTOVF;
ksi.ksi_addr = (void *)pc;
break;
}
if (sig != 0) {
ksi.ksi_signo = sig;
trapsignal(l, &ksi);
}
userret(l, pc, sticks);
share_fpu(l, tf);
#undef ADVANCE
}
int
rwindow_save(struct lwp *l)
{
struct pcb *pcb = lwp_getpcb(l);
struct rwindow *rw = &pcb->pcb_rw[0];
int i;
i = pcb->pcb_nsaved;
if (i < 0) {
pcb->pcb_nsaved = 0;
return (0);
}
if (i == 0)
return (0);
#ifdef DEBUG
if (rwindow_debug)
printf("cpu%d:%s[%d]: rwindow: pcb->stack:",
cpuinfo.ci_cpuid, l->l_proc->p_comm, l->l_proc->p_pid);
#endif
do {
#ifdef DEBUG
if (rwindow_debug)
printf(" [%d]0x%x", cpuinfo.ci_cpuid, rw[1].rw_in[6]);
#endif
if (copyout((void *)rw, (void *)rw[1].rw_in[6],
sizeof *rw))
return (-1);
rw++;
} while (--i > 0);
#ifdef DEBUG
if (rwindow_debug)
printf("\n");
#endif
pcb->pcb_nsaved = 0;
return (0);
}
void
cpu_vmspace_exec(struct lwp *l, vaddr_t vstart, vaddr_t vend)
{
struct pcb *pcb = lwp_getpcb(l);
write_user_windows();
pcb->pcb_nsaved = 0;
}
void
mem_access_fault(unsigned type, int ser, u_int v, int pc, int psr,
struct trapframe *tf)
{
#if defined(SUN4) || defined(SUN4C)
struct proc *p;
struct lwp *l;
struct pcb *pcb;
struct vmspace *vm;
vaddr_t va;
int rv;
vm_prot_t atype;
vaddr_t onfault;
u_quad_t sticks;
char bits[64];
ksiginfo_t ksi;
curcpu()->ci_data.cpu_ntrap++;
l = curlwp;
p = l->l_proc;
pcb = lwp_getpcb(l);
onfault = (vaddr_t)pcb->pcb_onfault;
sticks = p->p_sticks;
#ifdef FPU_DEBUG
if ((tf->tf_psr & PSR_EF) != 0) {
if (cpuinfo.fplwp != l)
panic("FPU enabled but wrong proc (1) [l=%p, fwlp=%p]",
l, cpuinfo.fplwp);
savefpstate(l->l_md.md_fpstate);
l->l_md.md_fpu = NULL;
cpuinfo.fplwp = NULL;
tf->tf_psr &= ~PSR_EF;
setpsr(getpsr() & ~PSR_EF);
}
#endif
if (type == T_TEXTFAULT)
v = pc;
if (VA_INHOLE(v)) {
rv = EACCES;
goto fault;
}
atype = ser & SER_WRITE ? VM_PROT_WRITE : VM_PROT_READ;
if ((ser & SER_PROT) && atype == VM_PROT_READ && type != T_TEXTFAULT) {
u_int insn;
if (ufetch_int((void *)pc, &insn) == 0 &&
(insn & 0xc1680000) == 0xc0680000) {
atype = VM_PROT_READ | VM_PROT_WRITE;
}
}
va = trunc_page(v);
if (psr & PSR_PS) {
if (type == T_TEXTFAULT) {
(void) splhigh();
snprintb(bits, sizeof(bits), SER_BITS, ser);
printf("cpu%d: text fault: pc=0x%x ser=%s\n",
cpu_number(), pc, bits);
panic("kernel fault");
}
if (onfault == (vaddr_t)sparc_fsbail) {
rv = EFAULT;
goto kfault;
}
if (cold) {
rv = EFAULT;
goto kfault;
}
if (va >= KERNBASE) {
rv = mmu_pagein(pmap_kernel(), va, atype);
if (rv < 0) {
rv = EACCES;
goto kfault;
}
if (rv > 0)
return;
pcb->pcb_onfault = NULL;
rv = uvm_fault(kernel_map, va, atype);
pcb->pcb_onfault = (void *)onfault;
if (rv == 0)
return;
goto kfault;
}
} else {
l->l_md.md_tf = tf;
}
vm = p->p_vmspace;
rv = mmu_pagein(vm->vm_map.pmap, va, atype);
if (rv < 0) {
rv = EACCES;
goto fault;
}
if (rv > 0)
goto out;
pcb->pcb_onfault = NULL;
rv = uvm_fault(&vm->vm_map, (vaddr_t)va, atype);
pcb->pcb_onfault = (void *)onfault;
if ((void *)va >= vm->vm_maxsaddr
#ifdef COMPAT_SUNOS
&& !(p->p_emul == &emul_sunos && va < USRSTACK -
(vaddr_t)p->p_limit->pl_rlimit[RLIMIT_STACK].rlim_cur +
SUNOS_MAXSADDR_SLOP)
#endif
&& rv == 0)
uvm_grow(p, va);
if (rv == 0) {
(void) mmu_pagein(vm->vm_map.pmap, va, VM_PROT_NONE);
} else {
fault:
if (psr & PSR_PS) {
kfault:
if (!onfault) {
(void) splhigh();
snprintb(bits, sizeof(bits), SER_BITS, ser);
printf("cpu%d: data fault: pc=0x%x "
"addr=0x%x ser=%s\n",
cpu_number(), pc, v, bits);
panic("kernel fault");
}
tf->tf_pc = onfault;
tf->tf_npc = onfault + 4;
tf->tf_out[0] = (rv == EACCES) ? EFAULT : rv;
return;
}
KSI_INIT_TRAP(&ksi);
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;
}
ksi.ksi_trap = type;
ksi.ksi_addr = (void *)v;
trapsignal(l, &ksi);
}
out:
if ((psr & PSR_PS) == 0) {
userret(l, pc, sticks);
share_fpu(l, tf);
}
#endif
}
#if defined(SUN4M)
static int tfaultaddr = (int) 0xdeadbeef;
void
mem_access_fault4m(unsigned type, u_int sfsr, u_int sfva, struct trapframe *tf)
{
int pc, psr;
struct proc *p;
struct lwp *l;
struct pcb *pcb;
struct vmspace *vm;
vaddr_t va;
int rv;
vm_prot_t atype;
int onfault;
u_quad_t sticks;
char bits[64];
ksiginfo_t ksi;
curcpu()->ci_data.cpu_ntrap++;
l = curlwp;
p = l->l_proc;
sticks = p->p_sticks;
pcb = lwp_getpcb(l);
onfault = (vaddr_t)pcb->pcb_onfault;
#ifdef FPU_DEBUG
if ((tf->tf_psr & PSR_EF) != 0) {
if (cpuinfo.fplwp != l)
panic("FPU enabled but wrong proc (2) [l=%p, fwlp=%p]",
l, cpuinfo.fplwp);
savefpstate(l->l_md.md_fpstate);
l->l_md.md_fpu = NULL;
cpuinfo.fplwp = NULL;
tf->tf_psr &= ~PSR_EF;
setpsr(getpsr() & ~PSR_EF);
}
#endif
pc = tf->tf_pc;
psr = tf->tf_psr;
#if 1
if (type == T_DATAERROR || type == T_TEXTERROR)
printf("%s[%d]: trap 0x%x: pc=0x%x sfsr=0x%x sfva=0x%x\n",
p->p_comm, p->p_pid, type, pc, sfsr, sfva);
#endif
if (type == T_STOREBUFFAULT ||
(type == T_DATAFAULT && (sfsr & SFSR_FAV) == 0)) {
(*cpuinfo.memerr)(type, sfsr, sfva, tf);
goto out_nounlock;
}
if ((sfsr & SFSR_FT) == SFSR_FT_NONE)
goto out;
if ((sfsr & SFSR_FAV) == 0) {
if ((type & ~0x20) == T_TEXTFAULT)
sfva = pc;
else {
rv = EACCES;
goto fault;
}
}
if ((sfsr & SFSR_FT) == SFSR_FT_TRANSERR) {
rv = EACCES;
if (tfaultaddr == sfva)
goto fault;
tfaultaddr = sfva;
if ((lda((sfva & 0xFFFFF000) | ASI_SRMMUFP_LN, ASI_SRMMUFP) &
SRMMU_TETYPE) != SRMMU_TEPTE)
goto fault;
lda(SRMMU_SFSR, ASI_SRMMU);
#ifdef DEBUG
printf("mem_access_fault4m: SFSR_FT_TRANSERR: "
"pid %d, va 0x%x: retrying\n", p->p_pid, sfva);
#endif
goto out;
}
va = trunc_page(sfva);
if (((sfsr & SFSR_AT_TEXT) || type == T_TEXTFAULT) &&
!(sfsr & SFSR_AT_STORE) && (sfsr & SFSR_OW)) {
if (psr & PSR_PS) {
rv = EFAULT;
goto kfault;
}
#if 0
if (cpuinfo.cpu_type == CPUTYP_HS_MBUS) {
vm = p->p_vmspace;
pcb->pcb_onfault = NULL;
rv = uvm_fault(&vm->vm_map, trunc_page(pc),
VM_PROT_READ);
pcb->pcb_onfault = onfault;
if (rv != 0)
#ifdef DEBUG
printf("mem_access_fault: "
"can't pagein 1st text fault.\n")
#endif
;
}
#endif
}
if (sfsr & SFSR_AT_STORE) {
atype = VM_PROT_WRITE;
} else {
if ((sfsr & SFSR_AT_TEXT) || (type & ~0x20) == T_TEXTFAULT) {
atype = VM_PROT_EXECUTE;
} else {
atype = VM_PROT_READ;
}
}
if (psr & PSR_PS) {
if (sfsr & SFSR_AT_TEXT || type == T_TEXTFAULT) {
(void) splhigh();
snprintb(bits, sizeof(bits), SFSR_BITS, sfsr);
printf("cpu%d text fault: pc=0x%x sfsr=%s sfva=0x%x\n",
cpu_number(), pc, bits, sfva);
panic("kernel fault");
}
if (onfault == (vaddr_t)sparc_fsbail) {
rv = EFAULT;
goto kfault;
}
if (cold) {
rv = EFAULT;
goto kfault;
}
if (va >= KERNBASE) {
pcb->pcb_onfault = NULL;
rv = uvm_fault(kernel_map, va, atype);
pcb->pcb_onfault = (void *)onfault;
if (rv == 0) {
return;
}
goto kfault;
}
} else {
l->l_md.md_tf = tf;
}
vm = p->p_vmspace;
pcb->pcb_onfault = NULL;
rv = uvm_fault(&vm->vm_map, (vaddr_t)va, atype);
pcb->pcb_onfault = (void *)onfault;
if (rv == 0 && (void *)va >= vm->vm_maxsaddr)
uvm_grow(p, va);
if (rv != 0) {
fault:
if (psr & PSR_PS) {
kfault:
if (!onfault) {
(void) splhigh();
snprintb(bits, sizeof(bits), SFSR_BITS, sfsr);
printf("cpu%d: data fault: pc=0x%x "
"addr=0x%x sfsr=%s\n",
cpu_number(), pc, sfva, bits);
panic("kernel fault");
}
tf->tf_pc = onfault;
tf->tf_npc = onfault + 4;
tf->tf_out[0] = (rv == EACCES) ? EFAULT : rv;
return;
}
KSI_INIT_TRAP(&ksi);
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;
}
ksi.ksi_trap = type;
ksi.ksi_addr = (void *)sfva;
trapsignal(l, &ksi);
}
out:
if ((psr & PSR_PS) == 0) {
out_nounlock:
userret(l, pc, sticks);
share_fpu(l, tf);
}
}
#endif
void
startlwp(void *arg)
{
ucontext_t *uc = arg;
lwp_t *l = curlwp;
int error __diagused;
error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
KASSERT(error == 0);
kmem_free(uc, sizeof(ucontext_t));
userret(l, l->l_md.md_tf->tf_pc, 0);
}