#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.199 2024/12/28 13:48:07 martin Exp $");
#include "opt_ddb.h"
#include "opt_multiprocessor.h"
#include "opt_compat_netbsd32.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/pool.h>
#include <sys/proc.h>
#include <sys/ras.h>
#include <sys/kernel.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 <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>
#ifdef DDB
#include <machine/db_machdep.h>
#else
#include <machine/frame.h>
#endif
#include <sparc64/sparc64/cache.h>
#include <sparc/fpu/fpu_extern.h>
#ifndef offsetof
#define offsetof(s, f) ((size_t)&((s *)0)->f)
#endif
#ifdef TRAPSTATS
int protfix = 0;
int udmiss = 0;
int udhit = 0;
int udprot = 0;
int utmiss = 0;
int kdmiss = 0;
int kdhit = 0;
int kdprot = 0;
int ktmiss = 0;
int iveccnt = 0;
int uintrcnt = 0;
int kiveccnt = 0;
int kintrcnt = 0;
int intristk = 0;
int intrpoll = 0;
int wfill = 0;
int kwfill = 0;
int wspill = 0;
int wspillskip = 0;
int rftucnt = 0;
int rftuld = 0;
int rftudone = 0;
int rftkcnt[5] = { 0, 0, 0, 0, 0 };
#endif
#ifdef DEBUG
#define RW_64 0x1
#define RW_ERR 0x2
#define RW_FOLLOW 0x4
int rwindow_debug = RW_ERR;
#define TDB_ADDFLT 0x1
#define TDB_TXTFLT 0x2
#define TDB_TRAP 0x4
#define TDB_SYSCALL 0x8
#define TDB_FOLLOW 0x10
#define TDB_FRAME 0x20
#define TDB_NSAVED 0x40
#define TDB_TL 0x80
#define TDB_STOPSIG 0x100
#define TDB_STOPCALL 0x200
#define TDB_STOPCPIO 0x400
#define TDB_SYSTOP 0x800
int trapdebug = 0;
#endif
#ifdef DDB
#if 1
#define DEBUGGER(t,f) do { kdb_trap(t,f); } while (0)
#else
#define DEBUGGER(t,f) Debugger()
#endif
#else
#define DEBUGGER(t,f)
#define Debugger()
#endif
struct evcnt ecc_corrected =
EVCNT_INITIALIZER(EVCNT_TYPE_MISC,0,"ECC","corrected");
EVCNT_ATTACH_STATIC(ecc_corrected);
const struct fpstate64 initfpstate __aligned(SPARC64_BLOCK_SIZE) = {
.fs_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,
~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 },
.fs_qsize = 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,
"+fast ECC error",
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)
void trap(struct trapframe64 *, unsigned int, vaddr_t, long);
void data_access_fault(struct trapframe64 *, unsigned int, vaddr_t, vaddr_t,
vaddr_t, u_long);
void data_access_error(struct trapframe64 *, unsigned int, vaddr_t, u_long,
vaddr_t, u_long);
void text_access_fault(struct trapframe64 *tf, unsigned int type, vaddr_t pc,
u_long sfsr);
void text_access_error(struct trapframe64 *, unsigned int, vaddr_t, u_long,
vaddr_t, u_long);
void ecc_corrected_error(unsigned int type, vaddr_t pc);
#ifdef DEBUG
void print_trapframe(struct trapframe64 *);
void
print_trapframe(struct trapframe64 *tf)
{
printf("Trapframe %p:\ttstate: %lx\tpc: %lx\tnpc: %lx\n",
tf, (u_long)tf->tf_tstate, (u_long)tf->tf_pc, (u_long)tf->tf_npc);
printf("fault: %p\ty: %x\t",
(void *)(u_long)tf->tf_fault, (int)tf->tf_y);
printf("pil: %d\toldpil: %d\ttt: %x\nGlobals:\n",
(int)tf->tf_pil, (int)tf->tf_oldpil, (int)tf->tf_tt);
printf("%08x%08x %08x%08x %08x%08x %08x%08x\n",
(u_int)(tf->tf_global[0]>>32), (u_int)tf->tf_global[0],
(u_int)(tf->tf_global[1]>>32), (u_int)tf->tf_global[1],
(u_int)(tf->tf_global[2]>>32), (u_int)tf->tf_global[2],
(u_int)(tf->tf_global[3]>>32), (u_int)tf->tf_global[3]);
printf("%08x%08x %08x%08x %08x%08x %08x%08x\nOuts:\n",
(u_int)(tf->tf_global[4]>>32), (u_int)tf->tf_global[4],
(u_int)(tf->tf_global[5]>>32), (u_int)tf->tf_global[5],
(u_int)(tf->tf_global[6]>>32), (u_int)tf->tf_global[6],
(u_int)(tf->tf_global[7]>>32), (u_int)tf->tf_global[7]);
#ifdef DEBUG
printf("%08x%08x %08x%08x %08x%08x %08x%08x\n",
(u_int)(tf->tf_out[0]>>32), (u_int)tf->tf_out[0],
(u_int)(tf->tf_out[1]>>32), (u_int)tf->tf_out[1],
(u_int)(tf->tf_out[2]>>32), (u_int)tf->tf_out[2],
(u_int)(tf->tf_out[3]>>32), (u_int)tf->tf_out[3]);
printf("%08x%08x %08x%08x %08x%08x %08x%08x\nLocals:\n",
(u_int)(tf->tf_out[4]>>32), (u_int)tf->tf_out[4],
(u_int)(tf->tf_out[5]>>32), (u_int)tf->tf_out[5],
(u_int)(tf->tf_out[6]>>32), (u_int)tf->tf_out[6],
(u_int)(tf->tf_out[7]>>32), (u_int)tf->tf_out[7]);
printf("%08x%08x %08x%08x %08x%08x %08x%08x\n",
(u_int)(tf->tf_local[0]>>32), (u_int)tf->tf_local[0],
(u_int)(tf->tf_local[1]>>32), (u_int)tf->tf_local[1],
(u_int)(tf->tf_local[2]>>32), (u_int)tf->tf_local[2],
(u_int)(tf->tf_local[3]>>32), (u_int)tf->tf_local[3]);
printf("%08x%08x %08x%08x %08x%08x %08x%08x\nIns:\n",
(u_int)(tf->tf_local[4]>>32), (u_int)tf->tf_local[4],
(u_int)(tf->tf_local[5]>>32), (u_int)tf->tf_local[5],
(u_int)(tf->tf_local[6]>>32), (u_int)tf->tf_local[6],
(u_int)(tf->tf_local[7]>>32), (u_int)tf->tf_local[7]);
printf("%08x%08x %08x%08x %08x%08x %08x%08x\n",
(u_int)(tf->tf_in[0]>>32), (u_int)tf->tf_in[0],
(u_int)(tf->tf_in[1]>>32), (u_int)tf->tf_in[1],
(u_int)(tf->tf_in[2]>>32), (u_int)tf->tf_in[2],
(u_int)(tf->tf_in[3]>>32), (u_int)tf->tf_in[3]);
printf("%08x%08x %08x%08x %08x%08x %08x%08x\n",
(u_int)(tf->tf_in[4]>>32), (u_int)tf->tf_in[4],
(u_int)(tf->tf_in[5]>>32), (u_int)tf->tf_in[5],
(u_int)(tf->tf_in[6]>>32), (u_int)tf->tf_in[6],
(u_int)(tf->tf_in[7]>>32), (u_int)tf->tf_in[7]);
#endif
}
#endif
void
trap(struct trapframe64 *tf, unsigned int type, vaddr_t pc, long tstate)
{
struct lwp *l;
struct proc *p;
struct pcb *pcb;
int64_t n;
u_quad_t sticks;
int pstate = tstate >> TSTATE_PSTATE_SHIFT;
ksiginfo_t ksi;
int error;
int code, sig;
#ifdef MULTIPROCESSOR
int s;
#define disintr() s = intr_disable()
#define rstintr() intr_restore(s)
#else
#define disintr()
#define rstintr()
#endif
#define ADVANCE (n = tf->tf_npc, tf->tf_pc = n, tf->tf_npc = n + 4)
#ifdef DEBUG
if (tf->tf_pc == tf->tf_npc) {
printf("trap: tpc %p == tnpc %p\n",
(void *)(u_long)tf->tf_pc, (void *)(u_long)tf->tf_npc);
Debugger();
}
if ((trapdebug & TDB_NSAVED && curpcb->pcb_nsaved) ||
trapdebug & (TDB_FOLLOW | TDB_TRAP)) {
char sbuf[sizeof(PSTATE_BITS) + 64];
printf("trap: type 0x%x: pc=%lx &tf=%p\n",
type, pc, tf);
snprintb(sbuf, sizeof(sbuf), PSTATE_BITS, pstate);
printf(" npc=%lx pstate=%s %s\n",
(long)tf->tf_npc, sbuf,
type < N_TRAP_TYPES ? trap_type[type] :
((type == T_AST) ? "ast" :
((type == T_RWRET) ? "rwret" : T)));
}
if ((trapdebug & (TDB_FOLLOW | TDB_TRAP)) ||
((trapdebug & TDB_TL) && gettl())) {
char sbuf[sizeof(PSTATE_BITS) + 64];
extern int trap_trace_dis;
trap_trace_dis = 1;
printf("trap: type 0x%x: lvl=%d pc=%lx &tf=%p",
type, gettl(), pc, tf);
snprintb(sbuf, sizeof(sbuf), PSTATE_BITS, pstate);
printf(" npc=%lx pstate=%s %s\n",
(long)tf->tf_npc, sbuf,
type < N_TRAP_TYPES ? trap_type[type] :
((type == T_AST) ? "ast" :
((type == T_RWRET) ? "rwret" : T)));
#ifdef DDB
kdb_trap(type, tf);
#endif
}
#endif
curcpu()->ci_data.cpu_ntrap++;
if (pstate & PSTATE_PRIV) {
#ifdef DDB
if (type == T_BREAKPOINT) {
write_all_windows();
if (kdb_trap(type, tf)) {
return;
}
}
if (type == T_PA_WATCHPT || type == T_VA_WATCHPT) {
if (kdb_trap(type, tf)) {
return;
}
}
#endif
if (type == T_FPDISABLED) {
struct lwp *newfplwp;
if (CLKF_INTR((struct clockframe *)tf) || !curlwp) {
newfplwp = &lwp0;
} else {
newfplwp = curlwp;
if (newfplwp->l_md.md_fpstate)
fpusave_lwp(newfplwp, true);
}
if (fplwp != newfplwp) {
disintr();
if (fplwp != NULL) {
KASSERT(fplwp->l_md.md_fpstate != NULL);
savefpstate(fplwp->l_md.md_fpstate);
fplwp = NULL;
}
rstintr();
if (newfplwp->l_md.md_fpstate != NULL) {
fplwp = newfplwp;
loadfpstate(fplwp->l_md.md_fpstate);
} else
fplwp = NULL;
}
tf->tf_tstate |= TSTATE_PEF;
return;
} else if (type == T_ECCERR) {
ecc_corrected_error(type, pc);
return;
} else if (type == T_FAST_ECC_ERROR) {
membar_Sync();
sp_blast_dcache_disabled(dcache_size, dcache_line_size);
return;
}
goto dopanic;
}
l = curlwp;
p = l->l_proc;
sticks = p->p_sticks;
pcb = lwp_getpcb(l);
l->l_md.md_tf = tf;
sig = 0;
switch (type) {
default:
if (type < 0x100) {
extern int trap_trace_dis;
dopanic:
trap_trace_dis = 1;
{
char sb[sizeof(PSTATE_BITS) + 64];
printf("trap type 0x%x: cpu %d, pc=%lx",
type, cpu_number(), pc);
snprintb(sb, sizeof(sb), PSTATE_BITS, pstate);
printf(" npc=%lx pstate=%s\n",
(long)tf->tf_npc, sb);
DEBUGGER(type, tf);
panic("%s", type < N_TRAP_TYPES ? trap_type[type] : T);
}
}
printf("%s[%d]: unimplemented software trap 0x%x\n",
p->p_comm, p->p_pid, type);
KSI_INIT_TRAP(&ksi);
sig = SIGILL;
ksi.ksi_trap = type;
ksi.ksi_code = ILL_ILLTRP;
ksi.ksi_addr = (void *)pc;
break;
case T_AST:
want_ast = 0;
if (l->l_pflag & LP_OWEUPC) {
l->l_pflag &= ~LP_OWEUPC;
ADDUPROF(l);
}
break;
case T_INST_EXCEPT:
case T_TEXTFAULT:
#ifdef DEBUG
printf("trap: pid=%d.%d comm=%s textfault at %lx!! sending SIGILL due to trap %d: %s\n",
l->l_proc->p_pid, l->l_lid, l->l_proc->p_comm,
pc, type, type < N_TRAP_TYPES ? trap_type[type] : T);
#endif
case T_ILLINST:
#if defined(DDB) && defined(DEBUG)
if (trapdebug & TDB_STOPSIG)
Debugger();
#endif
KSI_INIT_TRAP(&ksi);
sig = SIGILL;
ksi.ksi_trap = type;
ksi.ksi_code = ILL_ILLOPC;
ksi.ksi_addr = (void *)pc;
break;
case T_PRIVINST:
printf("trap: pid=%d.%d comm=%s privinst!! sending SIGILL due to trap %d: %s\n",
l->l_proc->p_pid, l->l_lid, l->l_proc->p_comm,
type, type < N_TRAP_TYPES ? trap_type[type] : T);
#if defined(DDB) && defined(DEBUG)
if (trapdebug & TDB_STOPSIG)
Debugger();
#endif
KSI_INIT_TRAP(&ksi);
sig = SIGILL;
ksi.ksi_trap = type;
ksi.ksi_code = ILL_PRVOPC;
ksi.ksi_addr = (void *)pc;
break;
case T_PRIVACT:
KSI_INIT_TRAP(&ksi);
sig = SIGILL;
ksi.ksi_trap = type;
ksi.ksi_code = ILL_PRVOPC;
ksi.ksi_addr = (void *)pc;
break;
case T_FPDISABLED: {
struct fpstate64 *fs = l->l_md.md_fpstate;
if (fs == NULL) {
fs = pool_cache_get(fpstate_cache, PR_WAITOK);
*fs = initfpstate;
l->l_md.md_fpstate = fs;
}
if (fs->fs_qsize) {
printf("trap: Warning fs_qsize is %d\n",fs->fs_qsize);
fpu_cleanup(l, fs);
break;
}
if (fplwp != l) {
fpusave_lwp(l, true);
disintr();
if (fplwp != NULL) {
KASSERT(fplwp->l_md.md_fpstate != NULL);
savefpstate(fplwp->l_md.md_fpstate);
}
loadfpstate(fs);
fplwp = l;
rstintr();
}
tf->tf_tstate |= TSTATE_PEF;
break;
}
case T_ALIGN:
case T_LDDF_ALIGN:
case T_STDF_ALIGN:
{
int64_t dsfsr = 0, dsfar = 0;
#ifdef DEBUG
int64_t isfsr = 0;
#endif
if (!CPU_ISSUN4V) {
dsfsr = ldxa(SFSR, ASI_DMMU);
if (dsfsr & SFSR_FV)
dsfar = ldxa(SFAR, ASI_DMMU);
} else {
paddr_t mmu_fsa_dfa = cpus->ci_mmufsa
+ offsetof(struct mmufsa, dfa);
dsfar = ldxa(mmu_fsa_dfa, ASI_PHYS_CACHED);
}
#ifdef DEBUG
if (!CPU_ISSUN4V) {
isfsr = ldxa(SFSR, ASI_IMMU);
} else {
paddr_t mmu_fsa_ifa = cpus->ci_mmufsa
+ offsetof(struct mmufsa, ifa);
isfsr = ldxa(mmu_fsa_ifa, ASI_PHYS_CACHED);
}
#endif
pcb = lwp_getpcb(l);
if (pcb && pcb->pcb_onfault) {
tf->tf_pc = (vaddr_t)pcb->pcb_onfault;
tf->tf_npc = tf->tf_pc + 4;
break;
}
#ifdef DEBUG
#define fmt64(x) (u_int)((x)>>32), (u_int)((x))
if (!CPU_ISSUN4V) {
printf("Alignment error: pid=%d.%d comm=%s dsfsr=%08x:%08x "
"dsfar=%x:%x isfsr=%08x:%08x pc=%lx\n",
l->l_proc->p_pid, l->l_lid, l->l_proc->p_comm, fmt64(dsfsr), fmt64(dsfar),
fmt64(isfsr), pc);
} else {
printf("Alignment error: pid=%d.%d comm=%s pc=%lx\n",
l->l_proc->p_pid, l->l_lid, l->l_proc->p_comm, pc);
paddr_t mmufsa_dfa_addr = cpus->ci_mmufsa + offsetof(struct mmufsa, dfa);
paddr_t mmufsa_dfc_addr = cpus->ci_mmufsa + offsetof(struct mmufsa, dfc);
int64_t dfa = ldxa(mmufsa_dfa_addr, ASI_PHYS_CACHED);
printf("dfa = %016lx\n", dfa);
int64_t dfc = ldxa(mmufsa_dfc_addr, ASI_PHYS_CACHED);
printf("dfc = %016lx\n", dfc);
}
#endif
#if defined(DDB) && defined(DEBUG)
if (trapdebug & TDB_STOPSIG) {
write_all_windows();
kdb_trap(type, tf);
}
#endif
if ((l->l_proc->p_md.md_flags & MDP_FIXALIGN) != 0 &&
fixalign(l, tf) == 0) {
ADVANCE;
break;
}
KSI_INIT_TRAP(&ksi);
sig = SIGBUS;
ksi.ksi_trap = type;
ksi.ksi_code = BUS_ADRALN;
ksi.ksi_addr = (void*)(intptr_t)dsfar;
}
break;
case T_FP_IEEE_754:
case T_FP_OTHER:
if (l != fplwp)
panic("fpe without being the FP user");
disintr();
KASSERT(l->l_md.md_fpstate != NULL);
savefpstate(l->l_md.md_fpstate);
fplwp = NULL;
rstintr();
if (l->l_md.md_fpstate->fs_qsize == 0) {
error = copyin((void *)pc,
&l->l_md.md_fpstate->fs_queue[0].fq_instr,
sizeof(int));
if (error) {
sig = SIGBUS;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = BUS_OBJERR;
ksi.ksi_addr = (void *)pc;
break;
}
l->l_md.md_fpstate->fs_qsize = 1;
code = fpu_cleanup(l, l->l_md.md_fpstate);
ADVANCE;
} else
code = fpu_cleanup(l, l->l_md.md_fpstate);
if (code != 0) {
sig = SIGFPE;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = code;
ksi.ksi_addr = (void *)pc;
}
break;
case T_TAGOF:
KSI_INIT_TRAP(&ksi);
sig = SIGEMT;
ksi.ksi_trap = type;
ksi.ksi_code = SI_NOINFO;
ksi.ksi_addr = (void *)pc;
break;
case T_BREAKPOINT:
if (p->p_raslist == NULL ||
(ras_lookup(p, (void *)(intptr_t)tf->tf_pc) == (void *)-1)) {
sig = SIGTRAP;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = TRAP_BRKPT;
ksi.ksi_addr = (void *)pc;
}
break;
case T_IDIV0:
case T_DIV0:
ADVANCE;
sig = SIGFPE;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = FPE_INTDIV;
ksi.ksi_addr = (void *)pc;
break;
case T_CLEANWIN:
uprintf("T_CLEANWIN\n");
ADVANCE;
break;
case T_FLUSHWIN:
write_all_windows();
ADVANCE;
break;
case T_RANGECHECK:
printf("T_RANGECHECK\n");
ADVANCE;
sig = SIGILL;
KSI_INIT_TRAP(&ksi);
ksi.ksi_trap = type;
ksi.ksi_code = ILL_ILLADR;
ksi.ksi_addr = (void *)pc;
break;
case T_FIXALIGN:
#ifdef DEBUG_ALIGN
uprintf("T_FIXALIGN\n");
#endif
l->l_proc->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;
case T_ECCERR:
ecc_corrected_error(type, pc);
break;
}
if (sig != 0) {
ksi.ksi_signo = sig;
trapsignal(l, &ksi);
}
userret(l, pc, sticks);
share_fpu(l, tf);
#undef ADVANCE
#ifdef DEBUG
if (trapdebug & (TDB_FOLLOW | TDB_TRAP)) {
printf("trap: done\n");
}
#endif
}
int
rwindow_save(struct lwp *l)
{
struct pcb *pcb = lwp_getpcb(l);
struct rwindow64 *rw = &pcb->pcb_rw[0];
uint64_t rwdest;
int i, j;
i = pcb->pcb_nsaved;
#ifdef DEBUG
if (rwindow_debug & RW_FOLLOW)
printf("rwindow_save(%p): nsaved %d\n", l, i);
#endif
if (i == 0)
return (0);
#ifdef DEBUG
if (rwindow_debug & RW_FOLLOW)
printf("%s[%d]: rwindow: pcb->stack:", l->l_proc->p_comm, l->l_proc->p_pid);
#endif
while (i > 0) {
rwdest = rw[i--].rw_in[6];
#ifdef DEBUG
if (rwindow_debug & RW_FOLLOW)
printf("window %d at %lx\n", i, (long)rwdest);
#endif
if (rwdest & 1) {
#ifdef DEBUG
if (rwindow_debug & RW_64) {
printf("rwindow_save: 64-bit tf to %p+BIAS "
"or %p\n",
(void *)(long)rwdest,
(void *)(long)(rwdest+BIAS));
Debugger();
}
#endif
rwdest += BIAS;
if (copyout((void *)&rw[i], (void *)(u_long)rwdest,
sizeof(*rw))) {
#ifdef DEBUG
if (rwindow_debug & (RW_ERR | RW_64))
printf("rwindow_save: 64-bit pcb copyout "
"to %p failed\n",
(void *)(long)rwdest);
#endif
return (-1);
}
#ifdef DEBUG
if (rwindow_debug & RW_64) {
printf("Finished copyout(%p, %p, %lx)\n",
(void *)&rw[i], (void *)(long)rwdest,
sizeof(*rw));
Debugger();
}
#endif
} else {
struct rwindow32 rwstack;
for (j = 0; j < 8; j++) {
rwstack.rw_local[j] = (int)rw[i].rw_local[j];
rwstack.rw_in[j] = (int)rw[i].rw_in[j];
}
if (copyout(&rwstack, (void *)(u_long)(u_int)rwdest,
sizeof(rwstack))) {
#ifdef DEBUG
if (rwindow_debug & RW_ERR)
printf("rwindow_save: 32-bit pcb "
"copyout to %p (%p) failed\n",
(void *)(u_long)(u_int)rwdest,
(void *)(u_long)rwdest);
#endif
return (-1);
}
}
}
pcb->pcb_nsaved = 0;
#ifdef DEBUG
if (rwindow_debug & RW_FOLLOW) {
printf("\n");
Debugger();
}
#endif
return (0);
}
void
cpu_vmspace_exec(struct lwp *l, vaddr_t start, vaddr_t end)
{
struct pcb *pcb = lwp_getpcb(l);
write_user_windows();
pcb->pcb_nsaved = 0;
}
void
data_access_fault(struct trapframe64 *tf, unsigned int type, vaddr_t pc,
vaddr_t addr, vaddr_t sfva, u_long sfsr)
{
uint64_t tstate;
struct lwp *l;
struct proc *p;
struct pcb *pcb;
struct vmspace *vm;
vaddr_t va;
int rv;
vm_prot_t access_type;
vaddr_t onfault;
u_quad_t sticks;
ksiginfo_t ksi;
#ifdef DEBUG
if (tf->tf_pc == tf->tf_npc) {
printf("data_access_fault: tpc %lx == tnpc %lx\n",
(long)tf->tf_pc, (long)tf->tf_npc);
Debugger();
}
write_user_windows();
if ((curpcb->pcb_nsaved > 8) ||
(trapdebug & TDB_NSAVED && curpcb->pcb_nsaved) ||
(trapdebug & (TDB_ADDFLT | TDB_FOLLOW))) {
printf("%ld: data_access_fault(%p, %x, %p, %p, %lx, %lx) "
"nsaved=%d\n",
(long)(curproc?curproc->p_pid:-1), tf, type,
(void *)pc, (void *)addr,
sfva, sfsr, (int)curpcb->pcb_nsaved);
#ifdef DDB
if ((trapdebug & TDB_NSAVED && curpcb->pcb_nsaved))
Debugger();
#endif
}
if (trapdebug & TDB_FRAME) {
print_trapframe(tf);
}
if ((trapdebug & TDB_TL) && gettl()) {
printf("%ld: data_access_fault(%p, %x, %p, %p, %lx, %lx) "
"nsaved=%d\n",
(long)(curproc?curproc->p_pid:-1), tf, type,
(void*)addr, (void*)pc,
sfva, sfsr, (int)curpcb->pcb_nsaved);
Debugger();
}
if (trapdebug & TDB_STOPCALL) {
Debugger();
}
#endif
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;
tstate = tf->tf_tstate;
#ifdef _LP64
if (__predict_false(addr >= (1UL<<HOLESHIFT) && addr < (1UL<<63))) {
if (tstate & TSTATE_PRIV) {
if (onfault) {
tf->tf_pc = onfault;
tf->tf_npc = onfault + 4;
tf->tf_out[0] = EFAULT;
return;
}
panic("fault type %u for invalid va %lx", type, addr);
}
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGSEGV;
ksi.ksi_code = SEGV_ACCERR;
ksi.ksi_trap = type;
ksi.ksi_addr = (void *)pc;
trapsignal(l, &ksi);
userret(l, pc, sticks);
share_fpu(l, tf);
return;
}
#endif
va = trunc_page(addr);
if (type == T_FDMMU_MISS || (sfsr & SFSR_FV) == 0) {
access_type = VM_PROT_READ;
} else {
access_type = (sfsr & SFSR_W) ? VM_PROT_WRITE : VM_PROT_READ;
}
if (tstate & TSTATE_PRIV) {
extern char Lfsbail[];
rv = EFAULT;
if (onfault == (vaddr_t)Lfsbail)
goto kfault;
if (cold)
goto kfault;
if (!(addr & TLB_TAG_ACCESS_CTX)) {
curpcb->pcb_onfault = NULL;
rv = uvm_fault(kernel_map, va, access_type);
curpcb->pcb_onfault = (void *)onfault;
#ifdef DEBUG
if (trapdebug & (TDB_ADDFLT | TDB_FOLLOW))
printf("cpu%d: data_access_fault: kernel "
"uvm_fault(%p, %lx, %x) "
"sez %x -- %s\n", cpu_number(),
kernel_map, va, access_type, rv,
rv ? "failure" : "success");
#endif
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, va, access_type);
pcb->pcb_onfault = (void *)onfault;
#ifdef DEBUG
if (trapdebug & (TDB_ADDFLT | TDB_FOLLOW))
printf("cpu%d: data_access_fault: %s uvm_fault(%p, %lx, %x) "
"sez %x -- %s\n", cpu_number(),
&vm->vm_map == kernel_map ? "kernel!!!" : "user",
&vm->vm_map, va, access_type, rv,
rv ? "failure" : "success");
#endif
if ((void *)va >= vm->vm_maxsaddr) {
if (rv == 0)
uvm_grow(p, va);
else if (rv == EACCES)
rv = EFAULT;
}
if (rv != 0) {
if (tstate & TSTATE_PRIV) {
kfault:
if (!onfault) {
extern int trap_trace_dis;
trap_trace_dis = 1;
(void) splhigh();
printf("cpu%d: data fault: pc=%lx rpc=%"PRIx64" addr=%lx\n",
cpu_number(), pc, tf->tf_in[7], addr);
DEBUGGER(type, tf);
panic("kernel fault");
}
#ifdef DEBUG
if (trapdebug &
(TDB_ADDFLT | TDB_FOLLOW | TDB_STOPCPIO)) {
printf("data_access_fault: copyin/out of %p "
"fault -- recover\n", (void *)addr);
DEBUGGER(type, tf);
}
#endif
tf->tf_pc = onfault;
tf->tf_npc = onfault + 4;
tf->tf_out[0] = (rv == EACCES) ? EFAULT : rv;
return;
}
#ifdef DEBUG
if (trapdebug & (TDB_ADDFLT | TDB_STOPSIG)) {
extern int trap_trace_dis;
trap_trace_dis = 1;
printf("cpu%d: data_access_fault at addr %p: "
"sending SIGSEGV\n", cpu_number(), (void *)addr);
printf("%ld: data_access_fault(%p, %x, %p, %p, "
"%lx, %lx) nsaved=%d\n",
(long)(curproc ? curproc->p_pid : -1), tf, type,
(void *)addr, (void *)pc,
sfva, sfsr, (int)curpcb->pcb_nsaved);
Debugger();
}
#endif
KSI_INIT_TRAP(&ksi);
switch (rv) {
case EINVAL:
ksi.ksi_signo = SIGBUS;
ksi.ksi_code = BUS_ADRERR;
break;
case EACCES:
ksi.ksi_signo = SIGSEGV;
ksi.ksi_code = SEGV_ACCERR;
break;
case ENOMEM:
ksi.ksi_signo = SIGKILL;
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);
break;
default:
ksi.ksi_signo = SIGSEGV;
ksi.ksi_code = SEGV_MAPERR;
break;
}
ksi.ksi_trap = type;
ksi.ksi_addr = (void *)sfva;
trapsignal(l, &ksi);
}
if ((tstate & TSTATE_PRIV) == 0) {
userret(l, pc, sticks);
share_fpu(l, tf);
}
#ifdef DEBUG
if (trapdebug & (TDB_ADDFLT | TDB_FOLLOW))
printf("data_access_fault: done\n");
if (trapdebug & TDB_FRAME) {
print_trapframe(tf);
}
if (trapdebug & (TDB_ADDFLT | TDB_FOLLOW)) {
extern void *return_from_trap(void);
if ((void *)(u_long)tf->tf_pc == (void *)return_from_trap) {
printf("Returning from stack datafault\n");
}
}
#endif
}
void
data_access_error(struct trapframe64 *tf, unsigned int type, vaddr_t afva,
u_long afsr, vaddr_t sfva, u_long sfsr)
{
u_long pc;
uint64_t tstate;
struct lwp *l;
struct pcb *pcb;
vaddr_t onfault;
u_quad_t sticks;
ksiginfo_t ksi;
#ifdef DEBUG
if (tf->tf_pc == tf->tf_npc) {
printf("data_access_error: tpc %lx == tnpc %lx\n",
(long)tf->tf_pc, (long)tf->tf_npc);
Debugger();
}
write_user_windows();
if ((trapdebug & TDB_NSAVED && curpcb->pcb_nsaved) ||
trapdebug & (TDB_ADDFLT | TDB_FOLLOW)) {
char buf[768];
snprintb(buf, sizeof buf, SFSR_BITS, sfsr);
printf("%d data_access_error(%lx, %lx, %lx, %p)=%lx @ %p %s\n",
curproc?curproc->p_pid:-1,
(long)type, (long)sfva, (long)afva, tf,
(long)tf->tf_tstate,
(void *)(u_long)tf->tf_pc, buf);
}
if (trapdebug & TDB_FRAME) {
print_trapframe(tf);
}
if ((trapdebug & TDB_TL) && gettl()) {
char buf[768];
snprintb(buf, sizeof buf, SFSR_BITS, sfsr);
printf("%d tl %d data_access_error(%lx, %lx, %lx, %p)="
"%lx @ %lx %s\n",
curproc ? curproc->p_pid : -1, gettl(),
(long)type, (long)sfva, (long)afva, tf,
(long)tf->tf_tstate,
(long)tf->tf_pc, buf);
Debugger();
}
if (trapdebug & TDB_STOPCALL) {
Debugger();
}
#endif
curcpu()->ci_data.cpu_ntrap++;
pc = tf->tf_pc;
tstate = tf->tf_tstate;
if (curcpu()->ci_pci_probe) {
#ifdef DIAGNOSTIC
printf("data_access_error in pci_conf_read: pc=%lx addr=%lx\n",
pc, afva);
#endif
curcpu()->ci_pci_fault = true;
tf->tf_npc = pc + 4;
return;
}
l = curlwp;
pcb = lwp_getpcb(l);
sticks = l->l_proc->p_sticks;
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) {
printf("data_access_error: no fault\n");
goto out;
}
if (tstate & TSTATE_PRIV) {
onfault = (vaddr_t)pcb->pcb_onfault;
if (!onfault) {
extern int trap_trace_dis;
char buf[768];
trap_trace_dis = 1;
snprintb(buf, sizeof buf, SFSR_BITS, sfsr);
(void) splhigh();
printf("data fault: pc=%lx addr=%lx sfsr=%s\n",
(u_long)pc, (long)sfva, buf);
DEBUGGER(type, tf);
panic("kernel fault");
}
if (afsr & ASFR_PRIV) {
char buf[128];
snprintb(buf, sizeof(buf), AFSR_BITS, afsr);
panic("Privileged Async Fault: AFAR %p AFSR %lx\n%s",
(void *)afva, afsr, buf);
}
#ifdef DEBUG
if (trapdebug & (TDB_ADDFLT | TDB_FOLLOW | TDB_STOPCPIO)) {
printf("data_access_error: kern fault -- "
"skipping instr\n");
if (trapdebug & TDB_STOPCPIO) {
DEBUGGER(type, tf);
}
}
#endif
tf->tf_pc = onfault;
tf->tf_npc = onfault + 4;
tf->tf_out[0] = EFAULT;
return;
}
#ifdef DEBUG
if (trapdebug & (TDB_ADDFLT | TDB_STOPSIG)) {
extern int trap_trace_dis;
trap_trace_dis = 1;
printf("data_access_error at %p: sending SIGSEGV\n",
(void *)(u_long)afva);
Debugger();
}
#endif
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGSEGV;
ksi.ksi_code = SEGV_MAPERR;
ksi.ksi_trap = type;
ksi.ksi_addr = (void *)afva;
trapsignal(l, &ksi);
out:
if ((tstate & TSTATE_PRIV) == 0) {
userret(l, pc, sticks);
share_fpu(l, tf);
}
#ifdef DEBUG
if (trapdebug & (TDB_ADDFLT | TDB_FOLLOW))
printf("data_access_error: done\n");
if (trapdebug & TDB_FRAME) {
print_trapframe(tf);
}
#endif
}
void
text_access_fault(struct trapframe64 *tf, unsigned int type, vaddr_t pc,
u_long sfsr)
{
uint64_t tstate;
struct lwp *l;
struct proc *p;
struct vmspace *vm;
vaddr_t va;
int rv;
vm_prot_t access_type;
u_quad_t sticks;
ksiginfo_t ksi;
#ifdef DEBUG
if (tf->tf_pc == tf->tf_npc) {
printf("text_access_fault: tpc %p == tnpc %p\n",
(void *)(u_long)tf->tf_pc, (void *)(u_long)tf->tf_npc);
Debugger();
}
write_user_windows();
if (((trapdebug & TDB_NSAVED) && curpcb->pcb_nsaved) ||
(trapdebug & (TDB_TXTFLT | TDB_FOLLOW)))
printf("%d text_access_fault(%x, %lx, %p)\n",
curproc?curproc->p_pid:-1, type, pc, tf);
if (trapdebug & TDB_FRAME) {
print_trapframe(tf);
}
if ((trapdebug & TDB_TL) && gettl()) {
printf("%d tl %d text_access_fault(%x, %lx, %p)\n",
curproc?curproc->p_pid:-1, gettl(), type, pc, tf);
Debugger();
}
if (trapdebug & TDB_STOPCALL) {
Debugger();
}
#endif
curcpu()->ci_data.cpu_ntrap++;
l = curlwp;
p = l->l_proc;
sticks = p->p_sticks;
tstate = tf->tf_tstate;
va = trunc_page(pc);
access_type = VM_PROT_EXECUTE;
if (tstate & TSTATE_PRIV) {
extern int trap_trace_dis;
trap_trace_dis = 1;
(void) splhigh();
printf("text_access_fault: pc=%lx va=%lx\n", pc, va);
DEBUGGER(type, tf);
panic("kernel fault");
} else
l->l_md.md_tf = tf;
vm = p->p_vmspace;
KASSERT(curpcb->pcb_onfault == NULL);
rv = uvm_fault(&vm->vm_map, va, access_type);
#ifdef DEBUG
if (trapdebug & (TDB_TXTFLT | TDB_FOLLOW))
printf("text_access_fault: uvm_fault(%p, %lx, %x) sez %x\n",
&vm->vm_map, va, access_type, rv);
#endif
if (rv != 0) {
#ifdef DEBUG
if (trapdebug & (TDB_TXTFLT | TDB_STOPSIG)) {
extern int trap_trace_dis;
trap_trace_dis = 1;
printf("text_access_fault at %p: sending SIGSEGV\n",
(void *)(u_long)va);
Debugger();
}
#endif
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGSEGV;
ksi.ksi_code = (rv == EACCES ? SEGV_ACCERR : SEGV_MAPERR);
ksi.ksi_trap = type;
ksi.ksi_addr = (void *)pc;
trapsignal(l, &ksi);
}
userret(l, pc, sticks);
share_fpu(l, tf);
#ifdef DEBUG
if (trapdebug & (TDB_TXTFLT | TDB_FOLLOW)) {
printf("text_access_fault: done\n");
}
if (trapdebug & TDB_FRAME) {
print_trapframe(tf);
}
#endif
}
void
text_access_error(struct trapframe64 *tf, unsigned int type, vaddr_t pc,
u_long sfsr, vaddr_t afva, u_long afsr)
{
int64_t tstate;
struct lwp *l;
struct proc *p;
struct vmspace *vm;
vaddr_t va;
int rv;
vm_prot_t access_type;
u_quad_t sticks;
ksiginfo_t ksi;
char buf[768];
#ifdef DEBUG
if (tf->tf_pc == tf->tf_npc) {
printf("text_access_error: tpc %p == tnpc %p\n",
(void *)(u_long)tf->tf_pc, (void *)(u_long)tf->tf_npc);
Debugger();
}
write_user_windows();
if ((trapdebug & TDB_NSAVED && curpcb->pcb_nsaved) ||
trapdebug & (TDB_TXTFLT | TDB_FOLLOW)) {
snprintb(buf, sizeof buf, SFSR_BITS, sfsr);
printf("%ld text_access_error(%lx, %lx, %lx, %p)=%lx @ %lx %s\n",
(long)(curproc?curproc->p_pid:-1),
(long)type, pc, (long)afva, tf, (long)tf->tf_tstate,
(long)tf->tf_pc, buf);
}
if (trapdebug & TDB_FRAME) {
print_trapframe(tf);
}
if ((trapdebug & TDB_TL) && gettl()) {
snprintb(buf, sizeof buf, SFSR_BITS, sfsr);
printf("%d tl %d text_access_error(%lx, %lx, %lx, %p)=%lx @ %lx %s\n",
curproc?curproc->p_pid:-1, gettl(),
(long)type, (long)pc, (long)afva, tf,
(long)tf->tf_tstate, (long)tf->tf_pc, buf);
Debugger();
}
if (trapdebug & TDB_STOPCALL) {
Debugger();
}
#endif
curcpu()->ci_data.cpu_ntrap++;
l = curlwp;
p = l->l_proc;
sticks = p->p_sticks;
tstate = tf->tf_tstate;
if ((afsr) != 0) {
extern int trap_trace_dis;
trap_trace_dis++;
printf("text_access_error: memory error...\n");
printf("text memory error type %d sfsr=%lx sfva=%lx afsr=%lx afva=%lx tf=%p\n",
type, sfsr, pc, afsr, afva, tf);
trap_trace_dis--;
if (tstate & TSTATE_PRIV)
panic("text_access_error: kernel memory error");
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGBUS;
ksi.ksi_code = BUS_OBJERR;
ksi.ksi_trap = type;
ksi.ksi_addr = (void *)afva;
trapsignal(l, &ksi);
}
if ((sfsr & SFSR_FV) == 0 || (sfsr & SFSR_FT) == 0)
goto out;
va = trunc_page(pc);
access_type = VM_PROT_EXECUTE;
if (tstate & TSTATE_PRIV) {
extern int trap_trace_dis;
trap_trace_dis = 1;
snprintb(buf, sizeof buf, SFSR_BITS, sfsr);
(void) splhigh();
printf("text error: pc=%lx sfsr=%s\n", pc, buf);
DEBUGGER(type, tf);
panic("kernel fault");
} else
l->l_md.md_tf = tf;
vm = p->p_vmspace;
KASSERT(curpcb->pcb_onfault == NULL);
rv = uvm_fault(&vm->vm_map, va, access_type);
if (rv != 0) {
#ifdef DEBUG
if (trapdebug & (TDB_TXTFLT | TDB_STOPSIG)) {
extern int trap_trace_dis;
trap_trace_dis = 1;
printf("text_access_error at %p: sending SIGSEGV\n",
(void *)(u_long)va);
Debugger();
}
#endif
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGSEGV;
ksi.ksi_code = (rv == EACCES ? SEGV_ACCERR : SEGV_MAPERR);
ksi.ksi_trap = type;
ksi.ksi_addr = (void *)pc;
trapsignal(l, &ksi);
}
out:
if ((tstate & TSTATE_PRIV) == 0) {
userret(l, pc, sticks);
share_fpu(l, tf);
}
#ifdef DEBUG
if (trapdebug & (TDB_TXTFLT | TDB_FOLLOW))
printf("text_access_error: done\n");
if (trapdebug & TDB_FRAME) {
print_trapframe(tf);
}
#endif
}
void
ecc_corrected_error(unsigned int type, vaddr_t pc)
{
uint64_t eeer, afar, afsr;
char buf[128];
int s;
eeer = ldxa(0, ASI_ERROR_EN_REG);
s = intr_disable();
stxa(0, ASI_ERROR_EN_REG,
eeer & ~(P_EER_NCEEN | P_EER_CEEN));
membar_Sync();
intr_restore(s);
blast_dcache();
blast_icache();
#if 0
cache_enable(PCPU_GET(impl));
#endif
afar = ldxa(0, ASI_AFAR);
afsr = ldxa(0, ASI_AFSR);
s = intr_disable();
stxa(0, ASI_AFSR, ldxa(0, ASI_AFSR));
membar_Sync();
intr_restore(s);
ecc_corrected.ev_count++;
snprintb(buf, sizeof(buf), AFSR_BITS, afsr);
printf("corrected ECC error: pc %p afsr %"PRIx64" (%s) addr %"PRIx64"\n", (void *)pc, afsr, buf, afar);
s = intr_disable();
stxa(0, ASI_ERROR_EN_REG, eeer);
membar_Sync();
intr_restore(s);
}