#include "opt_ddb.h"
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.17 2025/11/29 22:08:06 andvar Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/userret.h>
#include <uvm/uvm_extern.h>
#include <machine/frame.h>
#include <machine/md_var.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/ia64_cpu.h>
#include <machine/fpu.h>
#ifdef DDB
#include <machine/db_machdep.h>
#include <ddb/db_extern.h>
#endif
#include <ia64/disasm/disasm.h>
static const char *ia64_vector_names[] = {
"VHPT Translation",
"Instruction TLB",
"Data TLB",
"Alternate Instruction TLB",
"Alternate Data TLB",
"Data Nested TLB",
"Instruction Key Miss",
"Data Key Miss",
"Dirty-Bit",
"Instruction Access-Bit",
"Data Access-Bit",
"Break Instruction",
"External Interrupt",
"Reserved 13",
"Reserved 14",
"Reserved 15",
"Reserved 16",
"Reserved 17",
"Reserved 18",
"Reserved 19",
"Page Not Present",
"Key Permission",
"Instruction Access Rights",
"Data Access Rights",
"General Exception",
"Disabled FP-Register",
"NaT Consumption",
"Speculation",
"Reserved 28",
"Debug",
"Unaligned Reference",
"Unsupported Data Reference",
"Floating-point Fault",
"Floating-point Trap",
"Lower-Privilege Transfer Trap",
"Taken Branch Trap",
"Single Step Trap",
"Reserved 37",
"Reserved 38",
"Reserved 39",
"Reserved 40",
"Reserved 41",
"Reserved 42",
"Reserved 43",
"Reserved 44",
"IA-32 Exception",
"IA-32 Intercept",
"IA-32 Interrupt",
"Reserved 48",
"Reserved 49",
"Reserved 50",
"Reserved 51",
"Reserved 52",
"Reserved 53",
"Reserved 54",
"Reserved 55",
"Reserved 56",
"Reserved 57",
"Reserved 58",
"Reserved 59",
"Reserved 60",
"Reserved 61",
"Reserved 62",
"Reserved 63",
"Reserved 64",
"Reserved 65",
"Reserved 66",
"Reserved 67",
};
struct bitname {
uint64_t mask;
const char* name;
};
static void
printbits(uint64_t mask, struct bitname *bn, int count)
{
int i, first = 1;
uint64_t bit;
for (i = 0; i < count; i++) {
bit = bn[i].mask & ~(bn[i].mask - 1);
if (bn[i].mask > bit) {
if (first)
first = 0;
else
printf(",");
printf("%s=%ld", bn[i].name,
(mask & bn[i].mask) / bit);
} else if (mask & bit) {
if (first)
first = 0;
else
printf(",");
printf("%s", bn[i].name);
}
}
}
struct bitname psr_bits[] = {
{IA64_PSR_BE, "be"},
{IA64_PSR_UP, "up"},
{IA64_PSR_AC, "ac"},
{IA64_PSR_MFL, "mfl"},
{IA64_PSR_MFH, "mfh"},
{IA64_PSR_IC, "ic"},
{IA64_PSR_I, "i"},
{IA64_PSR_PK, "pk"},
{IA64_PSR_DT, "dt"},
{IA64_PSR_DFL, "dfl"},
{IA64_PSR_DFH, "dfh"},
{IA64_PSR_SP, "sp"},
{IA64_PSR_PP, "pp"},
{IA64_PSR_DI, "di"},
{IA64_PSR_SI, "si"},
{IA64_PSR_DB, "db"},
{IA64_PSR_LP, "lp"},
{IA64_PSR_TB, "tb"},
{IA64_PSR_RT, "rt"},
{IA64_PSR_CPL, "cpl"},
{IA64_PSR_IS, "is"},
{IA64_PSR_MC, "mc"},
{IA64_PSR_IT, "it"},
{IA64_PSR_ID, "id"},
{IA64_PSR_DA, "da"},
{IA64_PSR_DD, "dd"},
{IA64_PSR_SS, "ss"},
{IA64_PSR_RI, "ri"},
{IA64_PSR_ED, "ed"},
{IA64_PSR_BN, "bn"},
{IA64_PSR_IA, "ia"},
};
static void
printpsr(uint64_t psr)
{
printbits(psr, psr_bits, sizeof(psr_bits)/sizeof(psr_bits[0]));
}
struct bitname isr_bits[] = {
{IA64_ISR_CODE, "code"},
{IA64_ISR_VECTOR, "vector"},
{IA64_ISR_X, "x"},
{IA64_ISR_W, "w"},
{IA64_ISR_R, "r"},
{IA64_ISR_NA, "na"},
{IA64_ISR_SP, "sp"},
{IA64_ISR_RS, "rs"},
{IA64_ISR_IR, "ir"},
{IA64_ISR_NI, "ni"},
{IA64_ISR_SO, "so"},
{IA64_ISR_EI, "ei"},
{IA64_ISR_ED, "ed"},
};
static void printisr(uint64_t isr)
{
printbits(isr, isr_bits, sizeof(isr_bits)/sizeof(isr_bits[0]));
}
static void
printtrap(int vector, struct trapframe *tf, int isfatal, int user)
{
printf("\n");
printf("%s %s trap (cpu %lu):\n", isfatal? "fatal" : "handled",
user ? "user" : "kernel", curcpu()->ci_cpuid);
printf("\n");
printf(" trap vector = 0x%x (%s)\n",
vector, ia64_vector_names[vector]);
printf(" cr.iip = 0x%lx\n", tf->tf_special.iip);
printf(" cr.ipsr = 0x%lx (", tf->tf_special.psr);
printpsr(tf->tf_special.psr);
printf(")\n");
printf(" cr.isr = 0x%lx (", tf->tf_special.isr);
printisr(tf->tf_special.isr);
printf(")\n");
printf(" cr.ifa = 0x%lx\n", tf->tf_special.ifa);
if (tf->tf_special.psr & IA64_PSR_IS) {
printf(" ar.cflg = 0x%lx\n", ia64_get_cflg());
printf(" ar.csd = 0x%lx\n", ia64_get_csd());
printf(" ar.ssd = 0x%lx\n", ia64_get_ssd());
}
printf(" curlwp = %p\n", curlwp);
if (curproc != NULL)
printf(" pid = %d, comm = %s\n",
curproc->p_pid, curproc->p_comm);
printf("\n");
}
static uint64_t
trap_decode_break(struct trapframe *tf)
{
struct asm_bundle bundle;
struct asm_inst *inst;
int slot;
if (!asm_decode(tf->tf_special.iip, &bundle))
return (0);
slot = ((tf->tf_special.psr & IA64_PSR_RI) == IA64_PSR_RI_0) ? 0 :
((tf->tf_special.psr & IA64_PSR_RI) == IA64_PSR_RI_1) ? 1 : 2;
inst = bundle.b_inst + slot;
if (inst->i_op != ASM_OP_BREAK ||
inst->i_oper[1].o_type != ASM_OPER_IMM)
return (0);
return (inst->i_oper[1].o_value);
}
void
startlwp(void *arg)
{
panic("XXX %s implement", __func__);
}
#ifdef DDB
int call_debugger = 1;
int
ia64_trap(int type, int code, db_regs_t *regs)
{
ddb_regp = regs;
db_trap(type, code);
return 1;
}
#endif
void
trap_panic(int vector, struct trapframe *tf)
{
printtrap(vector, tf, 1, TRAPF_USERMODE(tf));
#ifdef DDB
if (ia64_trap(vector, 0, tf)) return;
#endif
panic("trap");
return;
}
int
do_ast(struct trapframe *tf)
{
printf("%s: not yet\n", __func__);
return 0;
}
void
trap(int vector, struct trapframe *tf)
{
struct proc *p;
struct lwp *l;
uint64_t ucode;
int sig, user;
ksiginfo_t ksi;
user = TRAPF_USERMODE(tf) ? 1 : 0;
l = curlwp;
ucode = 0;
#if 0
printtrap(vector, tf, 0, TRAPF_USERMODE(tf));
#endif
if (user) {
ia64_set_fpsr(IA64_FPSR_DEFAULT);
p = l->l_proc;
l->l_md.md_tf = tf;
} else {
p = NULL;
}
sig = 0;
switch (vector) {
case IA64_VEC_VHPT:
trap_panic(vector, tf);
break;
case IA64_VEC_ITLB:
case IA64_VEC_DTLB:
case IA64_VEC_EXT_INTR:
trap_panic(vector, tf);
break;
case IA64_VEC_ALT_ITLB:
case IA64_VEC_ALT_DTLB:
trap_panic(vector, tf);
break;
case IA64_VEC_NESTED_DTLB:
trap_panic(vector, tf);
break;
case IA64_VEC_IKEY_MISS:
case IA64_VEC_DKEY_MISS:
case IA64_VEC_KEY_PERMISSION:
trap_panic(vector, tf);
break;
case IA64_VEC_DIRTY_BIT:
case IA64_VEC_INST_ACCESS:
case IA64_VEC_DATA_ACCESS:
trap_panic(vector, tf);
break;
case IA64_VEC_BREAK:
if (user) {
ucode = (int)tf->tf_special.ifa & 0x1FFFFF;
if (ucode == 0) {
ucode = trap_decode_break(tf);
}
if (ucode < 0x80000) {
switch (ucode) {
case 0:
sig = SIGILL;
break;
case 1:
sig = SIGFPE;
ucode = FPE_INTDIV;
break;
case 2:
sig = SIGFPE;
ucode = FPE_INTOVF;
break;
case 3:
sig = SIGFPE;
ucode = FPE_FLTSUB;
break;
case 6:
case 7:
case 8:
case 9:
case 10:
sig = SIGFPE;
ucode = FPE_FLTINV;
break;
case 4:
case 5:
case 11:
sig = SIGSEGV;
break;
default:
sig = SIGILL;
break;
}
} else if (ucode < 0x100000) {
tf->tf_special.psr &= ~IA64_PSR_SS;
sig = SIGTRAP;
#if 0
} else if (ucode == 0x100000) {
break_syscall(tf);
return;
} else if (ucode == 0x180000) {
mcontext_t mc;
error = copyin((void*)tf->tf_scratch.gr8,
&mc, sizeof(mc));
if (!error) {
set_mcontext(td, &mc);
return;
}
sig = SIGSEGV;
ucode = tf->tf_scratch.gr8;
#endif
} else
sig = SIGILL;
} else {
trap_panic(vector, tf);
goto out;
}
break;
case IA64_VEC_PAGE_NOT_PRESENT:
case IA64_VEC_INST_ACCESS_RIGHTS:
case IA64_VEC_DATA_ACCESS_RIGHTS: {
struct pcb * const pcb = lwp_getpcb(l);
vaddr_t va;
struct vm_map *map;
vm_prot_t ftype;
uint64_t onfault;
int error = 0;
va = trunc_page(tf->tf_special.ifa);
if (va >= VM_MAXUSER_ADDRESS) {
if (user)
goto no_fault_in;
map = kernel_map;
} else {
map = (p != NULL) ? &p->p_vmspace->vm_map : NULL;
if (map == NULL)
goto no_fault_in;
}
if (tf->tf_special.isr & IA64_ISR_X)
ftype = VM_PROT_EXECUTE;
else if (tf->tf_special.isr & IA64_ISR_W)
ftype = VM_PROT_WRITE;
else
ftype = VM_PROT_READ;
onfault = pcb->pcb_onfault;
pcb->pcb_onfault = 0;
error = uvm_fault(map, va, ftype);
pcb->pcb_onfault = onfault;
if (error == 0)
goto out;
no_fault_in:
if (!user) {
if (pcb->pcb_onfault != 0) {
tf->tf_special.iip = pcb->pcb_onfault;
tf->tf_special.psr &= ~IA64_PSR_RI;
tf->tf_scratch.gr8 = error;
goto out;
}
trap_panic(vector, tf);
}
ucode = va;
sig = (error == EACCES) ? SIGBUS : SIGSEGV;
break;
}
case IA64_VEC_SPECULATION:
tf->tf_special.iip += tf->tf_special.ifa << 4;
tf->tf_special.psr &= ~IA64_PSR_RI;
goto out;
case IA64_VEC_DEBUG:
case IA64_VEC_SINGLE_STEP_TRAP:
tf->tf_special.psr &= ~IA64_PSR_SS;
if (!user) {
trap_panic(vector, tf);
goto out;
}
sig = SIGTRAP;
break;
default:
trap_panic(vector, tf);
break;
}
printf("sig = %d", sig);
KASSERT(sig != 0);
KSI_INIT(&ksi);
ksi.ksi_signo = sig;
ksi.ksi_code = ucode;
trapsignal(l, &ksi);
out:
if (user) {
mi_userret(l);
}
return;
}