#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux_trap.c,v 1.12 2021/10/07 12:52:27 msaitoh Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/acct.h>
#include <sys/kernel.h>
#include <sys/signal.h>
#include <sys/signalvar.h>
#include <sys/syscall.h>
#include <uvm/uvm_extern.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/trap.h>
#include <machine/userret.h>
#include <compat/linux/common/linux_exec.h>
#ifndef DEBUG_LINUX
#define DPRINTF(a)
#else
#define DPRINTF(a) uprintf a
#endif
struct linux_user_desc {
unsigned int entry_number;
unsigned int base_addr;
unsigned int limit;
unsigned int seg_32bit:1;
unsigned int contents:2;
unsigned int read_exec_only:1;
unsigned int limit_in_pages:1;
unsigned int seg_not_present:1;
unsigned int useable:1;
};
#define LINUX_T_DIVIDE 0
#define LINUX_T_DEBUG 1
#define LINUX_T_NMI 2
#define LINUX_T_INT3 3
#define LINUX_T_OVERFLOW 4
#define LINUX_T_BOUNDS 5
#define LINUX_T_INVALID_OP 6
#define LINUX_T_DEVICE_NOT_AVAIL 7
#define LINUX_T_DOUBLE_FAULT 8
#define LINUX_T_COPROC_SEG_OVERRUN 9
#define LINUX_T_INVALID_TSS 10
#define LINUX_T_SEG_NOT_PRESENT 11
#define LINUX_T_STACK_SEG_FAULT 12
#define LINUX_T_GENERAL_PROT_FAULT 13
#define LINUX_T_PAGE_FAULT 14
#define LINUX_T_SPURIOUS_INTERRUPT 15
#define LINUX_T_COPROC_ERROR 16
#define LINUX_T_ALIGN_CHECK 17
#define LINUX_T_MACHINE_CHECK 18
#define LINUX_T_SIMD_COPROC_ERROR 19
static const int trapno_to_x86_vec[] = {
LINUX_T_INVALID_OP,
LINUX_T_INT3,
LINUX_T_COPROC_ERROR,
LINUX_T_SPURIOUS_INTERRUPT,
LINUX_T_GENERAL_PROT_FAULT,
LINUX_T_DEBUG,
LINUX_T_PAGE_FAULT,
LINUX_T_ALIGN_CHECK,
LINUX_T_DIVIDE,
LINUX_T_NMI,
LINUX_T_OVERFLOW,
LINUX_T_BOUNDS,
LINUX_T_DEVICE_NOT_AVAIL,
LINUX_T_DOUBLE_FAULT,
LINUX_T_COPROC_SEG_OVERRUN,
LINUX_T_INVALID_TSS,
LINUX_T_SEG_NOT_PRESENT,
LINUX_T_STACK_SEG_FAULT,
LINUX_T_MACHINE_CHECK
};
static const int linux_x86_vec_to_sig[] = {
SIGFPE,
SIGTRAP,
SIGSEGV,
SIGTRAP,
SIGSEGV,
SIGSEGV,
SIGILL,
SIGSEGV,
SIGSEGV,
SIGFPE,
SIGSEGV,
SIGBUS,
SIGBUS,
SIGSEGV,
SIGSEGV,
SIGSEGV,
SIGFPE,
SIGSEGV,
SIGSEGV
};
void
linux_trapsignal(struct lwp *l, ksiginfo_t *ksi)
{
ksiginfo_t nksi;
switch (ksi->ksi_signo) {
case SIGILL:
case SIGTRAP:
case SIGIOT:
case SIGBUS:
case SIGFPE:
case SIGSEGV:
KASSERT(KSI_TRAP_P(ksi));
if (ksi->ksi_trap < __arraycount(trapno_to_x86_vec)) {
nksi = *ksi;
nksi.ksi_trap = trapno_to_x86_vec[ksi->ksi_trap];
if (nksi.ksi_trap < __arraycount(linux_x86_vec_to_sig)) {
nksi.ksi_signo
= linux_x86_vec_to_sig[nksi.ksi_trap];
} else {
uprintf("Unhandled sig type %d\n",
ksi->ksi_trap);
}
ksi = &nksi;
} else {
uprintf("Unhandled trap type %d\n", ksi->ksi_trap);
}
default:
trapsignal(l, ksi);
return;
}
}
int
linux_lwp_setprivate(struct lwp *l, void *ptr)
{
struct linux_user_desc info;
int error;
#ifdef __x86_64__
if ((l->l_proc->p_flag & PK_32) == 0) {
return lwp_setprivate(l, ptr);
}
#endif
error = copyin(ptr, &info, sizeof(info));
if (error)
return error;
DPRINTF(("linux_lwp_setprivate: %i, %x, %x, %i, %i, %i, %i, %i, %i\n",
info.entry_number, info.base_addr, info.limit, info.seg_32bit,
info.contents, info.read_exec_only, info.limit_in_pages,
info.seg_not_present, info.useable));
if (info.entry_number != GUGS_SEL) {
info.entry_number = GUGS_SEL;
error = copyout(&info, ptr, sizeof(info));
if (error)
return error;
}
return lwp_setprivate(l, (void *)(uintptr_t)info.base_addr);
}